diff --git a/Changelog.txt b/Changelog.txt index 334b985eb..2f77a506f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -51,6 +51,7 @@ Version 1.4.07 + Added new /mccooldowns command to show all ability cooldowns + Commands may now both print text and display a scoreboard + Killing a custom entity will automatically add it to the custom entity config file with default values. + = Fixed bug where arrow retrieval was not properly detecting entities that already existed in the tracker = Fixed bug which allowed players to bypass fishing's exploit prevention = Fixed bug where FakeEntityDamageByEntityEvent wasn't being fired = Fixed bug with "Skull Splitter" not finding the locale string diff --git a/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerCombatEvent.java b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerCombatEvent.java new file mode 100644 index 000000000..a5adb98ba --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/McMMOPlayerCombatEvent.java @@ -0,0 +1,33 @@ +package com.gmail.nossr50.events.skills; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import com.gmail.nossr50.datatypes.skills.SkillType; +import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent; +import com.gmail.nossr50.util.player.UserManager; + +public abstract class McMMOPlayerCombatEvent extends FakeEntityDamageByEntityEvent { + private Player player; + private SkillType skill; + private int skillLevel; + + public McMMOPlayerCombatEvent(Player player, Entity damager, Entity damagee, DamageCause cause, double damage, SkillType skill) { + super(damager, damagee, cause, damage); + this.player = player; + this.skill = skill; + skillLevel = UserManager.getPlayer(player).getProfile().getSkillLevel(skill); + } + + public Player getPlayer() { + return player; + } + + public SkillType getSkill() { + return skill; + } + + public int getSkillLevel() { + return skillLevel; + } +} diff --git a/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryCombatEvent.java b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryCombatEvent.java new file mode 100644 index 000000000..d05633688 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryCombatEvent.java @@ -0,0 +1,13 @@ +package com.gmail.nossr50.events.skills.archery; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import com.gmail.nossr50.datatypes.skills.SkillType; +import com.gmail.nossr50.events.skills.McMMOPlayerCombatEvent; + +public class McMMOPlayerArcheryCombatEvent extends McMMOPlayerCombatEvent { + public McMMOPlayerArcheryCombatEvent(Player player, Entity damager, Entity damagee, DamageCause cause, double damage) { + super(player, damager, damagee, cause, damage, SkillType.ARCHERY); + } +} diff --git a/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryEvent.java b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryEvent.java new file mode 100644 index 000000000..f9f9d1637 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerArcheryEvent.java @@ -0,0 +1,24 @@ +package com.gmail.nossr50.events.skills.archery; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; + +import com.gmail.nossr50.datatypes.skills.SkillType; +import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; + +public abstract class McMMOPlayerArcheryEvent extends McMMOPlayerSkillEvent implements Cancellable { + private boolean cancelled; + + protected McMMOPlayerArcheryEvent(Player player) { + super(player, SkillType.ARCHERY); + cancelled = false; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} diff --git a/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerDazeEvent.java b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerDazeEvent.java new file mode 100644 index 000000000..941bc9526 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerDazeEvent.java @@ -0,0 +1,12 @@ +package com.gmail.nossr50.events.skills.archery; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import com.gmail.nossr50.skills.archery.Archery; + +public class McMMOPlayerDazeEvent extends McMMOPlayerArcheryCombatEvent { + public McMMOPlayerDazeEvent(Player player, Entity damager, Entity damagee) { + super(player, damager, damagee, DamageCause.PROJECTILE, Archery.dazeModifier); + } +} diff --git a/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerSkillShotEvent.java b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerSkillShotEvent.java new file mode 100644 index 000000000..df7567e5d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/skills/archery/McMMOPlayerSkillShotEvent.java @@ -0,0 +1,10 @@ +package com.gmail.nossr50.events.skills.archery; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +public class McMMOPlayerSkillShotEvent extends McMMOPlayerArcheryCombatEvent { + public McMMOPlayerSkillShotEvent(Player player, Entity damager, Entity damagee, double damage) { + super(player, damager, damagee, DamageCause.PROJECTILE, damage); + } +} diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index bd3c96dec..c96185d1b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -74,7 +74,7 @@ public class EntityListener implements Listener { } projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(plugin, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0))); - projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, Archery.locationToString(projectile.getLocation()))); + projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation())); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -86,7 +86,7 @@ public class EntityListener implements Listener { } projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(plugin, 1.0)); - projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, Archery.locationToString(projectile.getLocation()))); + projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(plugin, projectile.getLocation())); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java index 9c8e1de2a..c58deb928 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java @@ -1,20 +1,18 @@ package com.gmail.nossr50.skills.archery; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; -import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.ItemStack; -import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.util.Misc; public class Archery { - private static List trackedEntities = new ArrayList(); + private static Map trackedEntities = new HashMap(); public static int retrieveMaxBonusLevel = AdvancedConfig.getInstance().getRetrieveMaxBonusLevel(); public static double retrieveMaxChance = AdvancedConfig.getInstance().getRetrieveChanceMax(); @@ -31,11 +29,11 @@ public class Archery { public static final double DISTANCE_XP_MULTIPLIER = 0.025; protected static void incrementTrackerValue(LivingEntity livingEntity) { - for (TrackedEntity trackedEntity : trackedEntities) { - if (trackedEntity.getLivingEntity().getEntityId() == livingEntity.getEntityId()) { - trackedEntity.incrementArrowCount(); - return; - } + TrackedEntity trackedEntity = trackedEntities.get(livingEntity.getUniqueId()); + + if (trackedEntity != null) { + trackedEntity.incrementArrowCount(); + return; } addToTracker(livingEntity); // If the entity isn't tracked yet @@ -45,11 +43,11 @@ public class Archery { TrackedEntity trackedEntity = new TrackedEntity(livingEntity); trackedEntity.incrementArrowCount(); - trackedEntities.add(trackedEntity); + trackedEntities.put(livingEntity.getUniqueId(), trackedEntity); } - protected static void removeFromTracker(TrackedEntity trackedEntity) { - trackedEntities.remove(trackedEntity); + protected static void removeFromTracker(UUID id) { + trackedEntities.remove(id); } /** @@ -58,24 +56,14 @@ public class Archery { * @param livingEntity The entity hit by the arrows */ public static void arrowRetrievalCheck(LivingEntity livingEntity) { - for (Iterator entityIterator = trackedEntities.iterator(); entityIterator.hasNext();) { - TrackedEntity trackedEntity = entityIterator.next(); + UUID id = livingEntity.getUniqueId(); + TrackedEntity trackedEntity = trackedEntities.get(id); - if (trackedEntity.getID() == livingEntity.getUniqueId()) { - Misc.dropItems(livingEntity.getLocation(), new ItemStack(Material.ARROW), trackedEntity.getArrowCount()); - entityIterator.remove(); - return; - } + if (trackedEntity == null) { + return; } - } - public static Location stringToLocation(String location) { - String[] values = location.split(","); - - return new Location(mcMMO.p.getServer().getWorld(values[0]), Double.parseDouble(values[1]), Double.parseDouble(values[2]), Double.parseDouble(values[3]), Float.parseFloat(values[4]), Float.parseFloat(values[5])); - } - - public static String locationToString(Location location) { - return location.getWorld().getName() + "," + location.getX() + "," + location.getY() + "," + location.getZ() + "," + location.getYaw() + "," + location.getPitch(); + Misc.dropItems(livingEntity.getLocation(), new ItemStack(Material.ARROW), trackedEntity.getArrowCount()); + removeFromTracker(id); } } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index a1718e9d7..ae91d9ae1 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -5,19 +5,19 @@ import org.bukkit.entity.Arrow; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SkillType; +import com.gmail.nossr50.events.skills.archery.McMMOPlayerDazeEvent; +import com.gmail.nossr50.events.skills.archery.McMMOPlayerSkillShotEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; -import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillUtils; public class ArcheryManager extends SkillManager { @@ -26,15 +26,15 @@ public class ArcheryManager extends SkillManager { } public boolean canDaze(LivingEntity target) { - return target instanceof Player && Permissions.daze(getPlayer()); + return target instanceof Player && Permissions.daze(getPlayer()) && SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Archery.dazeMaxBonus, Archery.dazeMaxBonusLevel); } - public boolean canSkillShot() { + public boolean canUseSkillShot() { return getSkillLevel() >= Archery.skillShotIncreaseLevel && Permissions.bonusDamage(getPlayer(), skill); } - public boolean canTrackArrows() { - return Permissions.arrowRetrieval(getPlayer()); + public boolean canTrack(Arrow arrow) { + return Permissions.arrowRetrieval(getPlayer()) && !arrow.hasMetadata(mcMMO.infiniteArrowKey) && SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Archery.retrieveMaxChance, Archery.retrieveMaxBonusLevel); } /** @@ -44,7 +44,7 @@ public class ArcheryManager extends SkillManager { * @param damager The {@link Entity} who shot the arrow */ public void distanceXpBonus(LivingEntity target, Entity damager) { - Location firedLocation = Archery.stringToLocation(damager.getMetadata(mcMMO.arrowDistanceKey).get(0).asString()); + Location firedLocation = (Location) damager.getMetadata(mcMMO.arrowDistanceKey).get(0).value(); Location targetLocation = target.getLocation(); if (firedLocation.getWorld() != targetLocation.getWorld()) { @@ -58,39 +58,52 @@ public class ArcheryManager extends SkillManager { * Track arrows fired for later retrieval. * * @param target The {@link LivingEntity} damaged by the arrow + * @param arrow The {@link Arrow} that damaged the target */ - public void trackArrows(LivingEntity target) { - if (SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Archery.retrieveMaxChance, Archery.retrieveMaxBonusLevel)) { - Archery.incrementTrackerValue(target); + public void trackArrow(LivingEntity target, Arrow arrow) { + if (!canTrack(arrow)) { + return; } + + Archery.incrementTrackerValue(target); } /** * Handle the effects of the Daze ability * - * @param defender The {@link Player} being affected by the ability + * @param target The {@link LivingEntity} being affected by the ability * @param arrow The {@link Arrow} that was fired */ - public double daze(Player defender, Arrow arrow) { - if (!SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Archery.dazeMaxBonus, Archery.dazeMaxBonusLevel)) { + public double daze(LivingEntity target, Arrow arrow) { + if (!canDaze(target)) { return 0; } + Player attacker = getPlayer(); + + McMMOPlayerDazeEvent event = new McMMOPlayerDazeEvent(attacker, arrow, target); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return 0; + } + + Player defender = (Player) target; Location dazedLocation = defender.getLocation(); dazedLocation.setPitch(90 - Misc.getRandom().nextInt(181)); defender.teleport(dazedLocation); - defender.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 20 * 10, 10)); + defender.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, Misc.TICK_CONVERSION_FACTOR * 10, 10)); if (UserManager.getPlayer(defender).useChatNotifications()) { defender.sendMessage(LocaleLoader.getString("Combat.TouchedFuzzy")); } if (mcMMOPlayer.useChatNotifications()) { - getPlayer().sendMessage(LocaleLoader.getString("Combat.TargetDazed")); + attacker.sendMessage(LocaleLoader.getString("Combat.TargetDazed")); } - return CombatUtils.callFakeDamageEvent(arrow, defender, DamageCause.PROJECTILE, Archery.dazeModifier); + return event.getDamage(); } /** @@ -101,9 +114,24 @@ public class ArcheryManager extends SkillManager { * @param arrow The {@link Arrow} that was fired */ public double skillShot(LivingEntity target, double damage, Arrow arrow) { + if (!canUseSkillShot()) { + return 0; + } + + McMMOPlayerSkillShotEvent event = new McMMOPlayerSkillShotEvent(getPlayer(), arrow, target, calculateSkillShotBonus(damage)); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return 0; + } + + return event.getDamage(); + } + + private double calculateSkillShotBonus(double damage) { double damageBonusPercent = Math.min(((getSkillLevel() / Archery.skillShotIncreaseLevel) * Archery.skillShotIncreasePercentage), Archery.skillShotMaxBonusPercentage); double archeryBonus = Math.min(damage * damageBonusPercent, Archery.skillShotMaxBonusDamage); - return CombatUtils.callFakeDamageEvent(arrow, target, DamageCause.PROJECTILE, archeryBonus); + return archeryBonus; } } diff --git a/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java b/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java index ef7e7993c..96a78867c 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/TrackedEntity.java @@ -22,15 +22,11 @@ public class TrackedEntity extends BukkitRunnable { @Override public void run() { if (!livingEntity.isValid()) { - Archery.removeFromTracker(this); + Archery.removeFromTracker(id); this.cancel(); } } - protected LivingEntity getLivingEntity() { - return livingEntity; - } - protected UUID getID() { return id; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 36b6ae0cc..41c64a85f 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -18,7 +18,6 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.inventory.ItemStack; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SkillType; @@ -167,18 +166,10 @@ public final class CombatUtils { } } - if (archeryManager.canSkillShot()) { - finalDamage += archeryManager.skillShot(target, initialDamage, arrow); - } - - if (archeryManager.canDaze(target)) { - finalDamage += archeryManager.daze((Player) target, arrow); - } - - if (!arrow.hasMetadata(mcMMO.infiniteArrowKey) && archeryManager.canTrackArrows()) { - archeryManager.trackArrows(target); - } + finalDamage += archeryManager.skillShot(target, initialDamage, arrow); + finalDamage += archeryManager.daze(target, arrow); + archeryManager.trackArrow(target, arrow); archeryManager.distanceXpBonus(target, arrow); event.setDamage(finalDamage);