package net.aufdemrand.denizen.events.entity; import net.aufdemrand.denizen.BukkitScriptEntryData; import net.aufdemrand.denizen.events.BukkitScriptEvent; import net.aufdemrand.denizen.objects.dEntity; import net.aufdemrand.denizen.objects.dInventory; import net.aufdemrand.denizen.objects.dItem; import net.aufdemrand.denizen.objects.dPlayer; import net.aufdemrand.denizen.utilities.DenizenAPI; import net.aufdemrand.denizencore.objects.Element; import net.aufdemrand.denizencore.objects.aH; import net.aufdemrand.denizencore.objects.dList; import net.aufdemrand.denizencore.objects.dObject; import net.aufdemrand.denizencore.scripts.ScriptEntryData; import net.aufdemrand.denizencore.scripts.containers.ScriptContainer; import net.aufdemrand.denizencore.utilities.CoreUtilities; import org.bukkit.Bukkit; import org.bukkit.entity.LivingEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.inventory.ItemStack; public class EntityDeathScriptEvent extends BukkitScriptEvent implements Listener { // <--[event] // @Events // entity death (in <area>) // entity dies (in <area>) // <entity> dies (in <area>) // <entity> death (in <area>) // // @Cancellable true // // @Regex ^on [^\s]+ (death|dies)( in ((notable (cuboid|ellipsoid))|([^\s]+)))?$ // // @Triggers when an entity dies. // // @Context // <context.entity> returns the dEntity that died. // <context.damager> returns the dEntity damaging the other entity, if any. // <context.message> returns an Element of a player's death message. // <context.inventory> returns the dInventory of the entity if it was a player. // <context.cause> returns an Element of the cause of the death. See <@link language damage cause> for a list of possible damage causes. // <context.drops> returns a dList of all pending item drops. // <context.xp> returns an Element of the amount of experience to be dropped. // // @Determine // Element to change the death message. // "NO_DROPS" to specify that any drops should be removed. // "NO_DROPS_OR_XP" to specify that any drops or XP orbs should be removed. // "NO_XP" to specify that any XP orbs should be removed. // dList(dItem) to specify new items to be dropped. // Element(Number) to specify the new amount of XP to be dropped. // "KEEP_INV" to specify (if a player death) that the inventory should be kept. // "KEEP_LEVEL" to specify (if a player death) that the XP level should be kept. // Note that the event can be cancelled to hide a player death message. // // @Player when the entity that died is a player. // // @NPC when the entity that died is an NPC. // // --> public EntityDeathScriptEvent() { instance = this; } public static EntityDeathScriptEvent instance; public dEntity entity; public dObject damager; public Element message; public dInventory inventory; public Element cause; public dList drops; public Integer xp; public boolean changed_drops; public boolean keep_inv; public boolean keep_level; public EntityDeathEvent event; @Override public boolean couldMatch(ScriptContainer scriptContainer, String s) { String cmd = CoreUtilities.getXthArg(1, CoreUtilities.toLowerCase(s)); return cmd.equals("dies") || cmd.equals("death"); } @Override public boolean matches(ScriptContainer scriptContainer, String s) { String lower = CoreUtilities.toLowerCase(s); String target = CoreUtilities.getXthArg(0, lower); if (!tryEntity(entity, target)) { return false; } if (!runInCheck(scriptContainer, s, lower, entity.getLocation())) { return false; } return true; } @Override public String getName() { return "EntityDies"; } @Override public void init() { Bukkit.getServer().getPluginManager().registerEvents(this, DenizenAPI.getCurrentInstance()); } @Override public void destroy() { EntityDeathEvent.getHandlerList().unregister(this); } @Override public boolean applyDetermination(ScriptContainer container, String determination) { // finish this String lower = CoreUtilities.toLowerCase(determination); // Deprecated if (lower.startsWith("drops ")) { lower = lower.substring(6); determination = determination.substring(6); } //Handle no_drops and no_drops_or_xp and just no_xp if (lower.startsWith("no_drops")) { drops.clear(); changed_drops = true; if (lower.endsWith("_or_xp")) { xp = 0; } } else if (lower.equals("no_xp")) { xp = 0; } else if (lower.equals("keep_inv")) { keep_inv = true; } else if (lower.equals("keep_level")) { keep_level = true; } // Change xp value only else if (aH.matchesInteger(determination)) { xp = aH.Argument.valueOf(lower).asElement().asInt(); } // Change dropped items if dList detected else if (aH.Argument.valueOf(lower).matchesArgumentList(dItem.class)) { drops.clear(); changed_drops = true; dList drops_list = dList.valueOf(determination); drops_list.filter(dItem.class); for (String drop : drops_list) { dItem item = dItem.valueOf(drop); if (item != null) { drops.add(item.identify()); // TODO: Why not just store the dItem in an arraylist? } } } else if (determination.equalsIgnoreCase("cancelled")) { cancelled = true; } // String containing new Death Message else if (event instanceof PlayerDeathEvent) { message = new Element(determination); } else { return super.applyDetermination(container, determination); } return true; } @Override public ScriptEntryData getScriptEntryData() { return new BukkitScriptEntryData(entity.isPlayer() ? dEntity.getPlayerFrom(event.getEntity()) : null, entity.isCitizensNPC() ? dEntity.getNPCFrom(event.getEntity()) : null); } @Override public dObject getContext(String name) { if (name.equals("entity")) { return entity.getDenizenObject(); } else if (name.equals("damager") && damager != null) { return damager; } else if (name.equals("message") && message != null) { return message; } else if (name.equals("inventory") && inventory != null) { return inventory; } else if (name.equals("cause") && cause != null) { return cause; } else if (name.equals("drops") && drops != null) { return drops; } else if (name.equals("xp") && xp != null) { return new Element(xp); } return super.getContext(name); } @EventHandler public void onEntityDeath(EntityDeathEvent event) { LivingEntity livingEntity = event.getEntity(); dEntity.rememberEntity(livingEntity); entity = new dEntity(livingEntity); dPlayer player = null; if (entity.isPlayer()) { player = entity.getDenizenPlayer(); } damager = null; EntityDamageEvent lastDamage = entity.getBukkitEntity().getLastDamageCause(); if (lastDamage != null) { if (lastDamage instanceof EntityDamageByEntityEvent) { damager = new dEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()).getDenizenObject(); } } message = null; inventory = null; PlayerDeathEvent subEvent = null; if (event instanceof PlayerDeathEvent) { subEvent = (PlayerDeathEvent) event; message = new Element(subEvent.getDeathMessage()); // Null check to prevent NPCs from causing an NPE if (player != null) { inventory = player.getInventory(); } keep_inv = subEvent.getKeepInventory(); keep_level = subEvent.getKeepLevel(); } cause = null; if (event.getEntity().getLastDamageCause() != null) { cause = new Element(event.getEntity().getLastDamageCause().getCause().toString()); } drops = new dList(); for (ItemStack stack : event.getDrops()) { if (stack == null) { drops.add("i@air"); } else { drops.add(new dItem(stack).identify()); } } changed_drops = false; xp = event.getDroppedExp(); this.event = event; fire(); event.setDroppedExp(xp); if (changed_drops) { event.getDrops().clear(); for (String drop : drops) { dItem item = dItem.valueOf(drop); if (item != null) { event.getDrops().add(item.getItemStack()); } } } if (event instanceof PlayerDeathEvent) { ((PlayerDeathEvent) event).setKeepInventory(keep_inv); ((PlayerDeathEvent) event).setKeepLevel(keep_level); } if (message != null && subEvent != null) { subEvent.setDeathMessage(message.asString()); } if (cancelled && subEvent != null) { subEvent.setDeathMessage(null); } dEntity.forgetEntity(livingEntity); } }