Bladeren bron

Added new active ability, Charge, to Taming

TfT_02 11 jaren geleden
bovenliggende
commit
58c1fcc64a

+ 1 - 0
Changelog.txt

@@ -8,6 +8,7 @@ Key:
   - Removal
 
 Version 1.5.02-dev
+ + Added new active ability "Charge" to Taming!
  + Added option to config.yml for Chimaera Wings to stop using bed spawn points
  = Fixed bug where no Mining XP was granted when Flux Mining was successful
  = Fixed bug where MobHealthbarTypes were not saved between server restarts

+ 6 - 0
src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java

@@ -18,6 +18,7 @@ public class TamingCommand extends SkillCommand {
     private String goreChance;
     private String goreChanceLucky;
 
+    private boolean canCharge;
     private boolean canBeastLore;
     private boolean canGore;
     private boolean canSharpenedClaws;
@@ -43,6 +44,7 @@ public class TamingCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
+        canCharge = Permissions.charge(player);
         canBeastLore = Permissions.secondaryAbilityEnabled(player, SecondaryAbility.BEAST_LORE);
         canCallWild = Permissions.callOfTheWild(player, EntityType.HORSE) || Permissions.callOfTheWild(player, EntityType.WOLF) || Permissions.callOfTheWild(player, EntityType.OCELOT);
         canEnvironmentallyAware = Permissions.secondaryAbilityEnabled(player, SecondaryAbility.ENVIROMENTALLY_AWARE);
@@ -58,6 +60,10 @@ public class TamingCommand extends SkillCommand {
     protected List<String> effectsDisplay() {
         List<String> messages = new ArrayList<String>();
 
+        if (canCharge) {
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.20"), LocaleLoader.getString("Taming.Effect.21")));
+        }
+
         if (canBeastLore) {
             messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.0"), LocaleLoader.getString("Taming.Effect.1")));
         }

+ 12 - 3
src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java

@@ -300,7 +300,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
                         writer.append(profile.getSkillXpLevel(SkillType.SWORDS)).append(":");
                         writer.append(profile.getSkillXpLevel(SkillType.AXES)).append(":");
                         writer.append(profile.getSkillXpLevel(SkillType.ACROBATICS)).append(":");
-                        writer.append(":");
+                        writer.append((int) profile.getAbilityDATS(AbilityType.CHARGE)).append(":");
                         writer.append(profile.getSkillLevel(SkillType.TAMING)).append(":");
                         writer.append(profile.getSkillXpLevel(SkillType.TAMING)).append(":");
                         writer.append((int) profile.getAbilityDATS(AbilityType.BERSERK)).append(":");
@@ -408,7 +408,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
                 out.append("0:"); // SwordsXp
                 out.append("0:"); // AxesXp
                 out.append("0:"); // AcrobaticsXp
-                out.append(":");
+                out.append("0:"); // DATS
                 out.append("0:"); // Taming
                 out.append("0:"); // TamingXp
                 out.append("0:"); // DATS
@@ -889,6 +889,15 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
                             }
                         }
 
+                        if (character[23].isEmpty()) {
+                            // Addition of "Charge" Taming ability
+                            // Version 1.5.02
+                            line = line.replace(character[23], "0:");
+                            if (oldVersion == null) {
+                                oldVersion = "1.5.02";
+                            }
+                        }
+
                         // If they're valid, rewrite them to the file.
                         if (character.length == 42) {
                             writer.append(line).append("\r\n");
@@ -1114,7 +1123,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
         skillsXp.put(SkillType.FISHING, (float) Integer.valueOf(character[35]));
         skillsXp.put(SkillType.ALCHEMY, (float) Integer.valueOf(character[40]));
 
-        // Taming - Unused
+        skillsDATS.put(AbilityType.CHARGE, Integer.valueOf(character[23]));
         skillsDATS.put(AbilityType.SUPER_BREAKER, Integer.valueOf(character[32]));
         // Repair - Unused
         skillsDATS.put(AbilityType.TREE_FELLER, Integer.valueOf(character[28]));

+ 12 - 12
src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java

@@ -315,18 +315,19 @@ public final class SQLDatabaseManager implements DatabaseManager {
             statement.close();
 
             statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET "
-                    + "  mining = ?, woodcutting = ?, unarmed = ?"
+                    + " taming = ?, mining = ?, woodcutting = ?, unarmed = ?"
                     + ", herbalism = ?, excavation = ?, swords = ?"
                     + ", axes = ?, blast_mining = ? WHERE user_id = ?");
-            statement.setLong(1, profile.getAbilityDATS(AbilityType.SUPER_BREAKER));
-            statement.setLong(2, profile.getAbilityDATS(AbilityType.TREE_FELLER));
-            statement.setLong(3, profile.getAbilityDATS(AbilityType.BERSERK));
-            statement.setLong(4, profile.getAbilityDATS(AbilityType.GREEN_TERRA));
-            statement.setLong(5, profile.getAbilityDATS(AbilityType.GIGA_DRILL_BREAKER));
-            statement.setLong(6, profile.getAbilityDATS(AbilityType.SERRATED_STRIKES));
-            statement.setLong(7, profile.getAbilityDATS(AbilityType.SKULL_SPLITTER));
-            statement.setLong(8, profile.getAbilityDATS(AbilityType.BLAST_MINING));
-            statement.setInt(9, id);
+            statement.setLong(1, profile.getAbilityDATS(AbilityType.CHARGE));
+            statement.setLong(2, profile.getAbilityDATS(AbilityType.SUPER_BREAKER));
+            statement.setLong(3, profile.getAbilityDATS(AbilityType.TREE_FELLER));
+            statement.setLong(4, profile.getAbilityDATS(AbilityType.BERSERK));
+            statement.setLong(5, profile.getAbilityDATS(AbilityType.GREEN_TERRA));
+            statement.setLong(6, profile.getAbilityDATS(AbilityType.GIGA_DRILL_BREAKER));
+            statement.setLong(7, profile.getAbilityDATS(AbilityType.SERRATED_STRIKES));
+            statement.setLong(8, profile.getAbilityDATS(AbilityType.SKULL_SPLITTER));
+            statement.setLong(9, profile.getAbilityDATS(AbilityType.BLAST_MINING));
+            statement.setInt(10, id);
             success = (statement.executeUpdate() != 0);
             statement.close();
 
@@ -932,7 +933,6 @@ public final class SQLDatabaseManager implements DatabaseManager {
      * Checks that the database structure is present and correct
      */
     private void checkStructure() {
-
         PreparedStatement statement = null;
         Statement createStatement = null;
         ResultSet resultSet = null;
@@ -1277,7 +1277,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         skillsXp.put(SkillType.FISHING, result.getFloat(OFFSET_XP + 12));
         skillsXp.put(SkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13));
 
-        // Taming - Unused - result.getInt(OFFSET_DATS + 1)
+        skillsDATS.put(AbilityType.CHARGE, result.getInt(OFFSET_DATS + 1));
         skillsDATS.put(AbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2));
         // Repair - Unused - result.getInt(OFFSET_DATS + 3)
         skillsDATS.put(AbilityType.TREE_FELLER, result.getInt(OFFSET_DATS + 4));

+ 30 - 3
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -5,12 +5,11 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
-import com.gmail.nossr50.runnables.skills.BleedTimerTask;
-import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import org.bukkit.GameMode;
 import org.bukkit.Location;
 import org.bukkit.Sound;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.metadata.FixedMetadataValue;
@@ -31,6 +30,7 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.party.ShareHandler;
 import com.gmail.nossr50.runnables.skills.AbilityDisableTask;
+import com.gmail.nossr50.runnables.skills.BleedTimerTask;
 import com.gmail.nossr50.runnables.skills.ToolLowerTask;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
@@ -46,6 +46,7 @@ import com.gmail.nossr50.skills.repair.RepairManager;
 import com.gmail.nossr50.skills.salvage.SalvageManager;
 import com.gmail.nossr50.skills.smelting.SmeltingManager;
 import com.gmail.nossr50.skills.swords.SwordsManager;
+import com.gmail.nossr50.skills.taming.Taming;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
@@ -53,6 +54,8 @@ import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.StringUtils;
+import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
@@ -739,6 +742,21 @@ public class McMMOPlayer {
             return;
         }
 
+        LivingEntity livingEntity = null;
+
+        if (ability == AbilityType.CHARGE) {
+            livingEntity = this.getTamingManager().getTarget(20);
+
+            if (!this.getTamingManager().isEntityTypeNearby(EntityType.WOLF, Taming.wolfCommandRange, true)) {
+                player.sendMessage(LocaleLoader.getString("Taming.Skills.Charge.NoneNearby"));
+                return;
+            }
+            else if (livingEntity == null) {
+                player.sendMessage(LocaleLoader.getString("Taming.Skills.Charge.NoTarget"));
+                return;
+            }
+        }
+
         if (EventUtils.callPlayerAbilityActivateEvent(player, skill).isCancelled()) {
             return;
         }
@@ -762,6 +780,10 @@ public class McMMOPlayer {
             SkillUtils.handleAbilitySpeedIncrease(player);
         }
 
+        if (ability == AbilityType.CHARGE) {
+            this.getTamingManager().handleCharge(livingEntity);
+        }
+
         new AbilityDisableTask(this, ability).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR);
     }
 
@@ -803,6 +825,11 @@ public class McMMOPlayer {
                 }
             }
 
+            if (ability == AbilityType.CHARGE && !this.getTamingManager().isEntityTypeNearby(EntityType.WOLF, Taming.wolfCommandRange, true)) {
+                player.sendMessage(LocaleLoader.getString("Taming.Skills.Charge.NoneNearby"));
+                return;
+            }
+
             if (Config.getInstance().getAbilityMessagesEnabled()) {
                 player.sendMessage(tool.getRaiseTool());
             }

+ 10 - 0
src/main/java/com/gmail/nossr50/datatypes/skills/AbilityType.java

@@ -60,6 +60,13 @@ public enum AbilityType {
             "Swords.Skills.SS.Refresh",
             "Swords.Skills.SS.Other.Off"),
 
+    CHARGE(
+            "Taming.Skills.Charge.On",
+            "Taming.Skills.Charge.Off",
+            "Taming.Skills.Charge.Other.On",
+            "Taming.Skills.Charge.Refresh",
+            "Taming.Skills.Charge.Other.Off"),
+
     /**
      * Has cooldown - but has to share a skill with Super Breaker, so needs special treatment
      */
@@ -152,6 +159,9 @@ public enum AbilityType {
             case BLAST_MINING:
                 return Permissions.remoteDetonation(player);
 
+            case CHARGE:
+                return Permissions.charge(player);
+
             case GIGA_DRILL_BREAKER:
                 return Permissions.gigaDrillBreaker(player);
 

+ 1 - 1
src/main/java/com/gmail/nossr50/datatypes/skills/SkillType.java

@@ -48,7 +48,7 @@ public enum SkillType {
     SALVAGE(SalvageManager.class, Color.ORANGE, ImmutableList.of(SecondaryAbility.ADVANCED_SALVAGE, SecondaryAbility.ARCANE_SALVAGE)),
     SMELTING(SmeltingManager.class, Color.YELLOW, ImmutableList.of(SecondaryAbility.FLUX_MINING, SecondaryAbility.FUEL_EFFICIENCY, SecondaryAbility.SECOND_SMELT)),
     SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), AbilityType.SERRATED_STRIKES, ToolType.SWORD, ImmutableList.of(SecondaryAbility.BLEED, SecondaryAbility.COUNTER)),
-    TAMING(TamingManager.class, Color.PURPLE, ImmutableList.of(SecondaryAbility.BEAST_LORE, SecondaryAbility.CALL_OF_THE_WILD, SecondaryAbility.ENVIROMENTALLY_AWARE, SecondaryAbility.FAST_FOOD, SecondaryAbility.GORE, SecondaryAbility.HOLY_HOUND, SecondaryAbility.SHARPENED_CLAWS, SecondaryAbility.SHOCK_PROOF, SecondaryAbility.THICK_FUR, SecondaryAbility.PUMMEL)),
+    TAMING(TamingManager.class, Color.PURPLE, AbilityType.CHARGE, ToolType.BONE, ImmutableList.of(SecondaryAbility.BEAST_LORE, SecondaryAbility.CALL_OF_THE_WILD, SecondaryAbility.ENVIROMENTALLY_AWARE, SecondaryAbility.FAST_FOOD, SecondaryAbility.GORE, SecondaryAbility.HOLY_HOUND, SecondaryAbility.SHARPENED_CLAWS, SecondaryAbility.SHOCK_PROOF, SecondaryAbility.THICK_FUR, SecondaryAbility.PUMMEL)),
     UNARMED(UnarmedManager.class, Color.BLACK, AbilityType.BERSERK, ToolType.FISTS, ImmutableList.of(SecondaryAbility.BLOCK_CRACKER, SecondaryAbility.DEFLECT, SecondaryAbility.DISARM, SecondaryAbility.IRON_ARM, SecondaryAbility.IRON_GRIP)),
     WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, AbilityType.TREE_FELLER, ToolType.AXE, ImmutableList.of(SecondaryAbility.LEAF_BLOWER, SecondaryAbility.WOODCUTTING_DOUBLE_DROPS));
 

+ 4 - 0
src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java

@@ -8,6 +8,7 @@ import com.gmail.nossr50.util.ItemUtils;
 
 public enum ToolType {
     AXE(LocaleLoader.getString("Axes.Ability.Lower"), LocaleLoader.getString("Axes.Ability.Ready")),
+    BONE(LocaleLoader.getString("Taming.Ability.Lower"), LocaleLoader.getString("Taming.Ability.Ready")),
     FISTS(LocaleLoader.getString("Unarmed.Ability.Lower"), LocaleLoader.getString("Unarmed.Ability.Ready")),
     HOE(LocaleLoader.getString("Herbalism.Ability.Lower"), LocaleLoader.getString("Herbalism.Ability.Ready")),
     PICKAXE(LocaleLoader.getString("Mining.Ability.Lower"), LocaleLoader.getString("Mining.Ability.Ready")),
@@ -41,6 +42,9 @@ public enum ToolType {
             case AXE:
                 return ItemUtils.isAxe(itemStack);
 
+            case BONE:
+                return itemStack.getType() == Material.BONE;
+
             case FISTS:
                 return itemStack.getType() == Material.AIR;
 

+ 9 - 1
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -39,6 +39,7 @@ import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.AbilityType;
 import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.datatypes.skills.ToolType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.party.ShareHandler;
 import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
@@ -522,10 +523,10 @@ public class PlayerListener implements Listener {
 
         McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         ItemStack heldItem = player.getItemInHand();
+        Block block = event.getClickedBlock();
 
         switch (event.getAction()) {
             case RIGHT_CLICK_BLOCK:
-                Block block = event.getClickedBlock();
                 BlockState blockState = block.getState();
 
                 /* ACTIVATION & ITEM CHECKS */
@@ -576,6 +577,7 @@ public class PlayerListener implements Listener {
                     mcMMOPlayer.processAbilityActivation(SkillType.SWORDS);
                     mcMMOPlayer.processAbilityActivation(SkillType.UNARMED);
                     mcMMOPlayer.processAbilityActivation(SkillType.WOODCUTTING);
+                    mcMMOPlayer.processAbilityActivation(SkillType.TAMING);
                 }
 
                 /* ITEM CHECKS */
@@ -590,6 +592,12 @@ public class PlayerListener implements Listener {
                 break;
 
             case LEFT_CLICK_AIR:
+                if (mcMMOPlayer.getToolPreparationMode(ToolType.BONE) && ToolType.BONE.inHand(heldItem)) {
+                    mcMMOPlayer.checkAbilityActivation(SkillType.TAMING);
+                }
+
+                // Fallthrough
+
             case LEFT_CLICK_BLOCK:
 
                 if (!player.isSneaking()) {

+ 2 - 0
src/main/java/com/gmail/nossr50/skills/taming/Taming.java

@@ -30,6 +30,8 @@ public class Taming {
     public static int    thickFurUnlockLevel = AdvancedConfig.getInstance().getThickFurUnlock();
     public static double thickFurModifier    = AdvancedConfig.getInstance().getThickFurModifier();
 
+    public static double wolfCommandRange = 10.0;
+
     public static int wolfXp   = ExperienceConfig.getInstance().getTamingXPWolf();
     public static int ocelotXp = ExperienceConfig.getInstance().getTamingXPOcelot();
     public static int horseXp  = ExperienceConfig.getInstance().getTamingXPHorse();

+ 105 - 27
src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java

@@ -15,6 +15,8 @@ import org.bukkit.entity.Player;
 import org.bukkit.entity.Tameable;
 import org.bukkit.entity.Wolf;
 import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.AdvancedConfig;
@@ -208,6 +210,81 @@ public class TamingManager extends SkillManager {
         owner.sendMessage(LocaleLoader.getString("Taming.Listener.Wolf"));
     }
 
+    public void handleCharge(LivingEntity livingEntity) {
+        attackTarget(livingEntity, true);
+    }
+
+    public LivingEntity getTarget(double range) {
+        Player player = getPlayer();
+        LivingEntity target = null;
+
+        for (Entity entity : player.getNearbyEntities(range, range, range)) {
+            if (!(entity instanceof LivingEntity) || entity.getType() == EntityType.WOLF || entity.getType() == EntityType.CREEPER || entity.equals(player)) {
+                continue;
+            }
+
+            if (!player.hasLineOfSight(entity)) {
+                continue;
+            }
+
+            target = (LivingEntity) entity;
+            break;
+        }
+
+        return target;
+    }
+
+    /**
+     * Make nearby wolves owned by the player attack the target
+     *
+     * @param target The LivingEntity to attack
+     *
+     * @return true if the attack was successful, false otherwise
+     */
+    public boolean attackTarget(LivingEntity target, boolean charge) {
+        boolean success = false;
+
+        for (Entity entity : getNearbyEntities(EntityType.WOLF, Taming.wolfCommandRange, true)) {
+            Wolf wolf = (Wolf) entity;
+
+            if (charge) {
+                charge(wolf);
+            }
+
+            wolf.setTarget(target);
+            success = true;
+        }
+
+        return success;
+    }
+
+    public boolean attackTarget(LivingEntity target) {
+        return attackTarget(target, false);
+    }
+
+    public void charge(Wolf wolf) {
+        int duration = 0;
+        int amplifier = 0;
+
+        if (wolf.hasPotionEffect(PotionEffectType.SPEED)) {
+            for (PotionEffect effect : wolf.getActivePotionEffects()) {
+                if (effect.getType() != PotionEffectType.SPEED) {
+                    continue;
+                }
+
+                duration = effect.getDuration();
+                amplifier = effect.getAmplifier();
+                break;
+            }
+        }
+
+        int ticks = 20 * 5;
+
+        PotionEffect abilityBuff = new PotionEffect(PotionEffectType.SPEED, duration + ticks, amplifier + 3);
+        wolf.addPotionEffect(abilityBuff, true);
+        ParticleEffectUtils.playSmokeEffect(wolf);
+    }
+
     public void pummel(LivingEntity target, Wolf wolf) {
         double chance = 10 / activationChance;
         SecondaryAbilityWeightedActivationCheckEvent event = new SecondaryAbilityWeightedActivationCheckEvent(getPlayer(), SecondaryAbility.PUMMEL, chance);
@@ -228,25 +305,6 @@ public class TamingManager extends SkillManager {
         }
     }
 
-    public void attackTarget(LivingEntity target) {
-        double range = 5;
-        Player player = getPlayer();
-
-        for (Entity entity : player.getNearbyEntities(range, range, range)) {
-            if (entity.getType() != EntityType.WOLF) {
-                continue;
-            }
-
-            Wolf wolf = (Wolf) entity;
-
-            if (!wolf.isTamed() || (wolf.getOwner() != player) || wolf.isSitting()) {
-                continue;
-            }
-
-            wolf.setTarget(target);
-        }
-    }
-
     /**
      * Handle the Call of the Wild ability.
      *
@@ -265,7 +323,8 @@ public class TamingManager extends SkillManager {
             return;
         }
 
-        if (!rangeCheck(type)) {
+        if (isEntityTypeNearby(type)) {
+            player.sendMessage(Taming.getCallOfTheWildFailureMessage(type));
             return;
         }
 
@@ -336,22 +395,41 @@ public class TamingManager extends SkillManager {
         player.playSound(location, Sound.FIREWORK_LARGE_BLAST2, 1F, 0.5F);
     }
 
-    private boolean rangeCheck(EntityType type) {
-        double range = Config.getInstance().getTamingCOTWRange();
+    public List<Entity> getNearbyEntities(EntityType type, double range, boolean wolfReady) {
+        List<Entity> nearbyEntities = new ArrayList<Entity>();
         Player player = getPlayer();
 
         if (range == 0) {
-            return true;
+            return nearbyEntities;
         }
 
         for (Entity entity : player.getNearbyEntities(range, range, range)) {
-            if (entity.getType() == type) {
-                player.sendMessage(Taming.getCallOfTheWildFailureMessage(type));
-                return false;
+            EntityType entityType = entity.getType();
+
+            if (entityType != type) {
+                continue;
+            }
+
+            if (entityType == EntityType.WOLF && wolfReady) {
+                Wolf wolf = (Wolf) entity;
+
+                if (!wolf.isTamed() || (wolf.getOwner() != player) || wolf.isSitting()) {
+                    continue;
+                }
             }
+
+            nearbyEntities.add(entity);
         }
 
-        return true;
+        return nearbyEntities;
+    }
+
+    public boolean isEntityTypeNearby(EntityType type) {
+        return isEntityTypeNearby(type, Config.getInstance().getTamingCOTWRange(), false);
+    }
+
+    public boolean isEntityTypeNearby(EntityType type, double range, boolean wolfReady) {
+        return !getNearbyEntities(type, range, wolfReady).isEmpty();
     }
 
     private boolean summonAmountCheck(EntityType entityType) {

+ 1 - 0
src/main/java/com/gmail/nossr50/util/Permissions.java

@@ -182,6 +182,7 @@ public final class Permissions {
     public static boolean serratedStrikes(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.swords.serratedstrikes"); }
 
     /* TAMING */
+    public static boolean charge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.taming.charge"); }
     public static boolean callOfTheWild(Permissible permissible, EntityType type) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild." + type.toString().toLowerCase()); }
     public static boolean renamePets(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild.renamepets"); }
 

+ 2 - 0
src/main/resources/config.yml

@@ -267,6 +267,7 @@ Abilities:
     Cooldowns:
         Berserk: 240
         Blast_Mining: 60
+        Charge: 240
         Giga_Drill_Breaker: 240
         Green_Terra: 240
         Serrated_Strikes: 240
@@ -276,6 +277,7 @@ Abilities:
     Max_Seconds:
         Berserk: 0
         Blast_Mining: 0
+        Charge: 0
         Giga_Drill_Breaker: 0
         Green_Terra: 0
         Serrated_Strikes: 0

+ 11 - 0
src/main/resources/locale/locale_en_US.properties

@@ -333,6 +333,8 @@ Taming.Ability.Locked.2=LOCKED UNTIL {0}+ SKILL (SHOCK PROOF)
 Taming.Ability.Locked.3=LOCKED UNTIL {0}+ SKILL (SHARPENED CLAWS)
 Taming.Ability.Locked.4=LOCKED UNTIL {0}+ SKILL (FAST FOOD SERVICE)
 Taming.Ability.Locked.5=LOCKED UNTIL {0}+ SKILL (HOLY HOUND)
+Taming.Ability.Lower=[[GRAY]]**YOUR WOLVES STAND DOWN**
+Taming.Ability.Ready=[[GREEN]]**YOU READY YOUR WOLVES**
 Taming.Combat.Chance.Gore=[[RED]]Gore Chance: [[YELLOW]]{0}
 Taming.Effect.0=Beast Lore
 Taming.Effect.1=Bone-whacking inspects wolves & ocelots
@@ -353,9 +355,18 @@ Taming.Effect.6=Environmentally Aware
 Taming.Effect.7=Cactus/Lava Phobia, Fall DMG Immune
 Taming.Effect.8=Thick Fur
 Taming.Effect.9=DMG Reduction, Fire Resistance
+Taming.Effect.20=Charge (ABILITY)
+Taming.Effect.21=Target Enemy, Wolf Speed++
 Taming.Listener.Wolf=[[DARK_GRAY]]Your wolf scurries back to you...
 Taming.Listener=Taming:
 Taming.SkillName=TAMING
+Taming.Skills.Charge.Off=[[RED]]**Charge has worn off**
+Taming.Skills.Charge.On=[[GREEN]]**CHARGE ACTIVATED**
+Taming.Skills.Charge.Other.Off=[[RED]]Charge[[GREEN]] has worn off for [[YELLOW]]{0}
+Taming.Skills.Charge.Other.On=[[GREEN]]{0}[[DARK_GREEN]] has used [[RED]]Charge!
+Taming.Skills.Charge.Refresh=[[GREEN]]Your [[YELLOW]]Charge [[GREEN]]ability is refreshed!
+Taming.Skills.Charge.NoneNearby=[[RED]]**NO AVAILABLE WOLVES NEARBY**
+Taming.Skills.Charge.NoTarget=[[RED]]**NO TARGET FOUND**
 Taming.Skillup=[[YELLOW]]Taming skill increased by {0}. Total ({1})
 Taming.Summon.Complete=[[GREEN]]Summoning complete
 Taming.Summon.Lifespan=[[YELLOW]] (Lifespan: {0}s)

+ 3 - 0
src/main/resources/plugin.yml

@@ -536,6 +536,7 @@ permissions:
             mcmmo.ability.taming.sharpenedclaws: true
             mcmmo.ability.taming.shockproof: true
             mcmmo.ability.taming.thickfur: true
+            mcmmo.ability.taming.charge: true
             mcmmo.ability.taming.pummel: true
     mcmmo.ability.taming.beastlore:
         description: Allows access to the Beast Lore ability
@@ -578,6 +579,8 @@ permissions:
         description: Allows access to the Shock Proof ability
     mcmmo.ability.taming.thickfur:
         description: Allows access to the Thick Fur ability
+    mcmmo.ability.taming.charge:
+        description: Allows access to the Charge ability
     mcmmo.ability.taming.pummel:
         description: Allows access to the Pummel ability
     mcmmo.ability.unarmed.*: