diff --git a/Changelog.txt b/Changelog.txt index 2173decb5..b4b7b9ac8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -25,6 +25,7 @@ Version 2.0.00-dev = Fixed bug where Tree Feller could be used without permissions = Fixed exploit where falling sand & gravel weren't tracked = Fixed exploit where Acrobatics could be leveled via Dodge on party members. + = Fixed exploit where you could gain combat XP on animals summoned by Call of the Wild ! Changed PTP to prevent teleporting if you've been hurt in the last 30 seconds (configurable) ! Changed Chimera Wing failure check to use the maxWorldHeight. ! Changed inspect failed message to say inspect rather than whois @@ -33,6 +34,8 @@ Version 2.0.00-dev ! Changed mmoedit to save a profile when used (this will make mctop update) ! Changed a few Runnable tasks to have their own classes ! Changed parties so that a player will leave their existing party if they enter a world where they don't have party permissions. + ! Changed Call of the Wild to summon animals already tamed. + ! Changed mob spawner tracking to use new Metadata API Version 1.3.02 + Added in game guides for Mining, Excavation, and Acrobatics. Simply type /skillname ? to access them diff --git a/src/main/java/com/gmail/nossr50/Combat.java b/src/main/java/com/gmail/nossr50/Combat.java index 0adf32a33..2dc2ce036 100644 --- a/src/main/java/com/gmail/nossr50/Combat.java +++ b/src/main/java/com/gmail/nossr50/Combat.java @@ -258,7 +258,7 @@ public class Combat { * @param dmg Amount of damage to attempt to do * @param attacker Player to pass to event as damager */ - public static void dealDamage(LivingEntity target, int dmg, Player attacker) { + private static void dealDamage(LivingEntity target, int dmg, Player attacker) { if (LoadProperties.eventCallback) { EntityDamageEvent ede = (EntityDamageByEntityEvent) new FakeEntityDamageByEntityEvent(attacker, target, EntityDamageEvent.DamageCause.ENTITY_ATTACK, dmg); Bukkit.getPluginManager().callEvent(ede); @@ -380,8 +380,7 @@ public class Combat { * @param skillType The skill being used * @param plugin mcMMO plugin instance */ - public static void startGainXp(Player attacker, PlayerProfile PP, LivingEntity target, SkillType skillType, mcMMO pluginx) - { + public static void startGainXp(Player attacker, PlayerProfile PP, LivingEntity target, SkillType skillType, mcMMO pluginx) { double baseXP = 0; if (target instanceof Player) { @@ -392,18 +391,15 @@ public class Combat { Player defender = (Player) target; PlayerProfile PPd = Users.getProfile(defender); - if (System.currentTimeMillis() >= (PPd.getRespawnATS() * 1000) + 5000 && - ((PPd.getLastLogin() + 5) * 1000) < System.currentTimeMillis() && - defender.getHealth() >= 1) { + if (System.currentTimeMillis() >= (PPd.getRespawnATS() * 1000) + 5000 && ((PPd.getLastLogin() + 5) * 1000) < System.currentTimeMillis() && defender.getHealth() >= 1) { baseXP = 20 * LoadProperties.pvpxprewardmodifier; } } - else if (!pluginx.misc.mobSpawnerList.contains(target.getEntityId())) { - if (target instanceof Animals) { - baseXP = LoadProperties.animalXP; //I'm assuming the 10x multiplier here was accidental... + else if (!target.hasMetadata("fromMobSpawner")) { + if (target instanceof Animals && !target.hasMetadata("summoned")) { + baseXP = LoadProperties.animalXP; } - else - { + else { EntityType type = target.getType(); switch (type) { @@ -471,5 +467,4 @@ public class Combat { Bukkit.getScheduler().scheduleSyncDelayedTask(pluginx, new GainXp(attacker, PP, skillType, baseXP, target), 0); } } - } diff --git a/src/main/java/com/gmail/nossr50/config/Misc.java b/src/main/java/com/gmail/nossr50/config/Misc.java index c6bd16f54..433508d65 100644 --- a/src/main/java/com/gmail/nossr50/config/Misc.java +++ b/src/main/java/com/gmail/nossr50/config/Misc.java @@ -15,7 +15,6 @@ public class Misc { String location = "mcmmo.properties"; - public ArrayList mobSpawnerList = new ArrayList(); public HashSet blockWatchList = new HashSet(); public HashMap arrowTracker = new HashMap(); public ArrayList bleedTracker = new ArrayList(); diff --git a/src/main/java/com/gmail/nossr50/listeners/mcEntityListener.java b/src/main/java/com/gmail/nossr50/listeners/mcEntityListener.java index 947e1660b..266b2e569 100644 --- a/src/main/java/com/gmail/nossr50/listeners/mcEntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/mcEntityListener.java @@ -20,6 +20,7 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityTameEvent; import org.bukkit.event.entity.ExplosionPrimeEvent; import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.metadata.FixedMetadataValue; import com.gmail.nossr50.Combat; import com.gmail.nossr50.Users; @@ -144,11 +145,6 @@ public class mcEntityListener implements Listener { LivingEntity x = event.getEntity(); x.setFireTicks(0); - /* Remove mob from mob spawner list */ - if (plugin.misc.mobSpawnerList.contains(x.getEntityId())) { - plugin.misc.mobSpawnerList.remove((Object)x.getEntityId()); - } - /* Remove bleed track */ if(plugin.misc.bleedTracker.contains(x)) { plugin.misc.addToBleedRemovalQue(x); @@ -169,7 +165,7 @@ public class mcEntityListener implements Listener { @EventHandler (priority = EventPriority.MONITOR) public void onCreatureSpawn(CreatureSpawnEvent event) { if (event.getSpawnReason().equals(SpawnReason.SPAWNER) && !LoadProperties.xpGainsMobSpawners) { - plugin.misc.mobSpawnerList.add(event.getEntity().getEntityId()); + event.getEntity().setMetadata("fromMobSpawner", new FixedMetadataValue(plugin, true)); } } @@ -291,7 +287,7 @@ public class mcEntityListener implements Listener { public void onEntityTame(EntityTameEvent event) { Player player = (Player) event.getOwner(); - if (mcPermissions.getInstance().taming(player)) { + if (mcPermissions.getInstance().taming(player) && !event.getEntity().hasMetadata("summoned")) { PlayerProfile PP = Users.getProfile(player); EntityType type = event.getEntityType(); int xp = 0; diff --git a/src/main/java/com/gmail/nossr50/listeners/mcPlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/mcPlayerListener.java index 88a93f21e..ce8ac9636 100644 --- a/src/main/java/com/gmail/nossr50/listeners/mcPlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/mcPlayerListener.java @@ -267,10 +267,10 @@ public class mcPlayerListener implements Listener { /* CALL OF THE WILD CHECKS */ if (player.isSneaking() && mcPermissions.getInstance().taming(player)) { if (is.getType().equals(Material.RAW_FISH)) { - Taming.animalSummon(EntityType.OCELOT, player); + Taming.animalSummon(EntityType.OCELOT, player, plugin); } else if (is.getType().equals(Material.BONE)) { - Taming.animalSummon(EntityType.WOLF, player); + Taming.animalSummon(EntityType.WOLF, player, plugin); } } diff --git a/src/main/java/com/gmail/nossr50/skills/Fishing.java b/src/main/java/com/gmail/nossr50/skills/Fishing.java index c1e0d73ba..58656fdc9 100644 --- a/src/main/java/com/gmail/nossr50/skills/Fishing.java +++ b/src/main/java/com/gmail/nossr50/skills/Fishing.java @@ -129,7 +129,7 @@ public class Fishing { final int ENCHANTMENT_CHANCE = 10; boolean enchanted = false; ItemStack fishingResults = theCatch.getItemStack(); - + player.sendMessage(mcLocale.getString("Fishing.ItemFound")); if (Repair.isArmor(fishingResults) || Repair.isTools(fishingResults)) { if (Math.random() * 100 <= ENCHANTMENT_CHANCE) { @@ -148,8 +148,8 @@ public class Fishing { enchanted = true; int randomEnchantLevel = (int) (Math.random() * newEnchant.getMaxLevel()) + 1; - if (randomEnchantLevel == 0) { - randomEnchantLevel = 1; + if (randomEnchantLevel < newEnchant.getStartLevel()) { + randomEnchantLevel = newEnchant.getStartLevel(); } fishingResults.addEnchantment(newEnchant, randomEnchantLevel); diff --git a/src/main/java/com/gmail/nossr50/skills/Skills.java b/src/main/java/com/gmail/nossr50/skills/Skills.java index 193ec9437..4287b05fe 100644 --- a/src/main/java/com/gmail/nossr50/skills/Skills.java +++ b/src/main/java/com/gmail/nossr50/skills/Skills.java @@ -428,12 +428,14 @@ public class Skills { activate = false; break; } + /* FALLS THROUGH */ case GREEN_TERRA: if (!ability.blockCheck(block.getType())) { activate = false; break; } + break; default: activate = false; diff --git a/src/main/java/com/gmail/nossr50/skills/Taming.java b/src/main/java/com/gmail/nossr50/skills/Taming.java index a5dc57bdb..f10d4243a 100644 --- a/src/main/java/com/gmail/nossr50/skills/Taming.java +++ b/src/main/java/com/gmail/nossr50/skills/Taming.java @@ -1,15 +1,17 @@ package com.gmail.nossr50.skills; import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.entity.AnimalTamer; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; import org.bukkit.entity.Wolf; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; import com.gmail.nossr50.Users; import com.gmail.nossr50.mcMMO; @@ -18,152 +20,206 @@ import com.gmail.nossr50.datatypes.PlayerProfile; import com.gmail.nossr50.datatypes.SkillType; import com.gmail.nossr50.locale.mcLocale; -public class Taming -{ - public static void fastFoodService(PlayerProfile PPo, Wolf theWolf, EntityDamageEvent event) - { - int health = theWolf.getHealth(); - int maxHealth = theWolf.getMaxHealth(); - int damage = event.getDamage(); - if(PPo.getSkillLevel(SkillType.TAMING) >= 50) - { - if(health < maxHealth) - { - if(Math.random() * 10 > 5) - { - if(health + damage <= maxHealth) - theWolf.setHealth(health + damage); - else - theWolf.setHealth(maxHealth); - } - } - } - } - - public static void sharpenedClaws(PlayerProfile PPo, EntityDamageEvent event) - { - if(PPo.getSkillLevel(SkillType.TAMING) >= 750) - { - event.setDamage(event.getDamage() + 2); - } - } - - public static void gore(PlayerProfile PPo, EntityDamageEvent event, Player master, mcMMO pluginx) - { - if(Math.random() * 1000 <= PPo.getSkillLevel(SkillType.TAMING)) - { - Entity entity = event.getEntity(); - event.setDamage(event.getDamage() * 2); - - if(entity instanceof Player) - { - Player target = (Player)entity; - target.sendMessage(mcLocale.getString("Combat.StruckByGore")); //$NON-NLS-1$ - Users.getProfile(target).setBleedTicks(2); - } - else - pluginx.misc.addToBleedQue((LivingEntity)entity); - - master.sendMessage(mcLocale.getString("Combat.Gore")); //$NON-NLS-1$ - } - } - - public static String getOwnerName(Wolf theWolf) - { - Player owner = null; - - if (theWolf.getOwner() instanceof Player) - { - owner = (Player)theWolf.getOwner(); - return owner.getName(); - } - else - return "Offline Master"; - } - - public static void preventDamage(EntityDamageEvent event, mcMMO plugin) - { - DamageCause cause = event.getCause(); - Wolf wolf = (Wolf) event.getEntity(); +public class Taming { + + /** + * Apply the Fast Food Service ability. + * + * @param PPo The PlayerProfile of the wolf's owner + * @param theWolf The wolf using the ability + * @param event The event to modify + */ + public static void fastFoodService (PlayerProfile PPo, Wolf theWolf, EntityDamageEvent event) { + final int SKILL_ACTIVATION_LEVEL = 50; + final int ACTIVATION_CHANCE = 50; + + int health = theWolf.getHealth(); + int maxHealth = theWolf.getMaxHealth(); + int damage = event.getDamage(); + + if (PPo.getSkillLevel(SkillType.TAMING) >= SKILL_ACTIVATION_LEVEL) { + if (health < maxHealth) { + if (Math.random() * 100 < ACTIVATION_CHANCE) { + if (health + damage <= maxHealth) { + theWolf.setHealth(health + damage); + } + else { + theWolf.setHealth(maxHealth); + } + } + } + } + } + + /** + * Apply the Sharpened Claws ability. + * + * @param PPo The PlayerProfile of the wolf's owner + * @param event The event to modify + */ + public static void sharpenedClaws(PlayerProfile PPo, EntityDamageEvent event) { + final int SKILL_ACTIVATION_LEVEL = 750; + final int SHARPENED_CLAWS_BONUS = 2; + + if (PPo.getSkillLevel(SkillType.TAMING) >= SKILL_ACTIVATION_LEVEL) { + event.setDamage(event.getDamage() + SHARPENED_CLAWS_BONUS); + } + } + + /** + * Apply the Gore ability. + * + * @param PPo The PlayerProfile of the wolf's owner + * @param event The event to modify + * @param master The wolf's master + * @param plugin mcMMO plugin instance + */ + public static void gore(PlayerProfile PPo, EntityDamageEvent event, Player master, mcMMO plugin) { + final int GORE_MULTIPLIER = 2; + + if (Math.random() * 1000 <= PPo.getSkillLevel(SkillType.TAMING)) { + Entity entity = event.getEntity(); + event.setDamage(event.getDamage() * GORE_MULTIPLIER); + + if (entity instanceof Player) { + Player target = (Player) entity; + + target.sendMessage(mcLocale.getString("Combat.StruckByGore")); + Users.getProfile(target).setBleedTicks(2); + } + else { + plugin.misc.addToBleedQue((LivingEntity)entity); + } + + master.sendMessage(mcLocale.getString("Combat.Gore")); + } + } + + /** + * Get the name of a wolf's owner. + * + * @param theWolf The wolf whose owner's name to get + * @return the name of the wolf's owner, or "Offline Master" if the owner is offline + */ + public static String getOwnerName(Wolf theWolf) { + AnimalTamer tamer = theWolf.getOwner(); + + if (tamer instanceof Player) { + Player owner = (Player) tamer; + return owner.getName(); + } + else { + return "Offline Master"; + } + } + + /** + * Prevent damage to wolves based on various skills. + * + * @param event The event to modify + * @param plugin mcMMO plugin instance + */ + public static void preventDamage(EntityDamageEvent event, mcMMO plugin) { + final int ENVIRONMENTALLY_AWARE_LEVEL = 100; + final int THICK_FUR_LEVEL = 250; + final int SHOCK_PROOF_LEVEL = 500; + + final int THICK_FUR_MODIFIER = 2; + final int SHOCK_PROOF_MODIFIER = 6; + + DamageCause cause = event.getCause(); + Wolf wolf = (Wolf) event.getEntity(); Player master = (Player) wolf.getOwner(); - int skillLevel = Users.getProfile(master).getSkillLevel(SkillType.TAMING); - - switch(cause) - { - //Environmentally Aware - case CONTACT: - case LAVA: - case FIRE: - if(skillLevel >= 100) - { - if(event.getDamage() >= wolf.getHealth()) - return; - - wolf.teleport(master.getLocation()); - master.sendMessage(mcLocale.getString("mcEntityListener.WolfComesBack")); //$NON-NLS-1$ - } - break; - case FALL: - if(skillLevel >= 100) - event.setCancelled(true); - break; - - //Thick Fur - case FIRE_TICK: - if(skillLevel >= 250) - wolf.setFireTicks(0); - break; - case ENTITY_ATTACK: - case PROJECTILE: - if(skillLevel >= 250) - event.setDamage(event.getDamage() / 2); - break; - - //Shock Proof - case ENTITY_EXPLOSION: - case BLOCK_EXPLOSION: - if(skillLevel >= 500) - event.setDamage(event.getDamage() / 6); - break; - } - } - - public static void animalSummon(EntityType type, Player player) - { - ItemStack item = player.getItemInHand(); - Material summonItem = null; - int summonAmount = 0; - - switch(type) - { - case WOLF: - summonItem = Material.BONE; - summonAmount = LoadProperties.bonesConsumedByCOTW; - break; - case OCELOT: - summonItem = Material.RAW_FISH; - summonAmount = LoadProperties.fishConsumedByCOTW; - break; - } - - if(item.getType().equals(summonItem) && item.getAmount() >= summonAmount) - { - for(Entity x : player.getNearbyEntities(40, 40, 40)) - { - if(x.getType().equals(type)) - { - player.sendMessage(mcLocale.getString("m.TamingSummonFailed")); - return; - } - } - - World world = player.getWorld(); - world.spawnCreature(player.getLocation(), type); - - int amount = item.getAmount(); - amount = amount - summonAmount; - player.setItemInHand(new ItemStack(summonItem, amount)); - player.sendMessage(mcLocale.getString("m.TamingSummon")); - } - } + int skillLevel = Users.getProfile(master).getSkillLevel(SkillType.TAMING); + + switch (cause) { + + /* Environmentally Aware */ + case CONTACT: + case LAVA: + case FIRE: + if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) { + if (event.getDamage() >= wolf.getHealth()) { + return; + } + + wolf.teleport(master.getLocation()); + master.sendMessage(mcLocale.getString("mcEntityListener.WolfComesBack")); + } + break; + + case FALL: + if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) { + event.setCancelled(true); + } + break; + + /* Thick Fur */ + case FIRE_TICK: + if(skillLevel >= THICK_FUR_LEVEL) { + wolf.setFireTicks(0); + } + break; + + case ENTITY_ATTACK: + case PROJECTILE: + if (skillLevel >= THICK_FUR_LEVEL) { + event.setDamage(event.getDamage() / THICK_FUR_MODIFIER); + } + break; + + /* Shock Proof */ + case ENTITY_EXPLOSION: + case BLOCK_EXPLOSION: + if (skillLevel >= SHOCK_PROOF_LEVEL) { + event.setDamage(event.getDamage() / SHOCK_PROOF_MODIFIER); + } + break; + + default: + break; + } + } + + /** + * Summon an animal. + * + * @param type Type of animal to summon + * @param player Player summoning the animal + */ + public static void animalSummon(EntityType type, Player player, mcMMO plugin) { + ItemStack item = player.getItemInHand(); + Material summonItem = null; + int summonAmount = 0; + + switch (type) { + case WOLF: + summonItem = Material.BONE; + summonAmount = LoadProperties.bonesConsumedByCOTW; + break; + + case OCELOT: + summonItem = Material.RAW_FISH; + summonAmount = LoadProperties.fishConsumedByCOTW; + break; + + default: + break; + } + + if (item.getType().equals(summonItem) && item.getAmount() >= summonAmount) { + for (Entity x : player.getNearbyEntities(40, 40, 40)) { + if (x.getType().equals(type)) { + player.sendMessage(mcLocale.getString("m.TamingSummonFailed")); + return; + } + } + LivingEntity entity = player.getWorld().spawnCreature(player.getLocation(), type); + entity.setMetadata("summoned", new FixedMetadataValue(plugin, true)); + ((Tameable) entity).setOwner(player); + + player.setItemInHand(new ItemStack(summonItem, item.getAmount() - summonAmount)); + player.sendMessage(mcLocale.getString("m.TamingSummon")); + } + } }