Ver código fonte

SkillUtils cleanup, EventUtils creation

Move some functions in SkillUtils to more relevant locations.

Begin work on utility class to handle all event calls.
GJ 11 anos atrás
pai
commit
468fbdab56
32 arquivos alterados com 408 adições e 503 exclusões
  1. 1 1
      src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
  2. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java
  3. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java
  4. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java
  5. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java
  6. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java
  7. 1 1
      src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java
  8. 1 1
      src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java
  9. 10 12
      src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java
  10. 2 3
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  11. 1 2
      src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java
  12. 1 1
      src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java
  13. 1 1
      src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java
  14. 147 2
      src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
  15. 2 6
      src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java
  16. 21 0
      src/main/java/com/gmail/nossr50/datatypes/skills/AbilityType.java
  17. 28 25
      src/main/java/com/gmail/nossr50/datatypes/skills/SkillType.java
  18. 9 9
      src/main/java/com/gmail/nossr50/listeners/BlockListener.java
  19. 18 17
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  20. 2 3
      src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java
  21. 1 1
      src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java
  22. 1 1
      src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java
  23. 2 1
      src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
  24. 2 1
      src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
  25. 62 0
      src/main/java/com/gmail/nossr50/util/EventUtils.java
  26. 4 4
      src/main/java/com/gmail/nossr50/util/HardcoreManager.java
  27. 1 2
      src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java
  28. 27 32
      src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java
  29. 13 14
      src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java
  30. 3 3
      src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java
  31. 41 350
      src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
  32. 1 0
      src/main/resources/locale/locale_en_US.properties

+ 1 - 1
src/main/java/com/gmail/nossr50/api/ExperienceAPI.java

@@ -414,7 +414,7 @@ public final class ExperienceAPI {
         int powerLevel = 0;
         PlayerProfile profile = getOfflineProfile(playerName);
 
-        for (SkillType type : SkillType.nonChildSkills()) {
+        for (SkillType type : SkillType.NON_CHILD_SKILLS) {
             powerLevel += profile.getSkillLevel(type);
         }
 

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java

@@ -7,7 +7,6 @@ import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class AddlevelsCommand extends ExperienceCommand {
     @Override
@@ -36,6 +35,6 @@ public class AddlevelsCommand extends ExperienceCommand {
 
     @Override
     protected void handlePlayerMessageSkill() {
-        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, SkillUtils.getSkillName(skill)));
+        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getSkillName()));
     }
 }

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java

@@ -5,7 +5,6 @@ import org.bukkit.command.CommandSender;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class AddxpCommand extends ExperienceCommand {
     @Override
@@ -35,6 +34,6 @@ public class AddxpCommand extends ExperienceCommand {
 
     @Override
     protected void handlePlayerMessageSkill() {
-        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, SkillUtils.getSkillName(skill)));
+        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getSkillName()));
     }
 }

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java

@@ -18,7 +18,6 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 import com.google.common.collect.ImmutableList;
 
@@ -149,7 +148,7 @@ public abstract class ExperienceCommand implements TabExecutor {
             sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
         }
         else {
-            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", SkillUtils.getSkillName(skill), playerName));
+            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getSkillName(), playerName));
         }
     }
 

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java

@@ -8,7 +8,6 @@ import com.gmail.nossr50.events.experience.McMMOPlayerLevelDownEvent;
 import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class MmoeditCommand extends ExperienceCommand {
     @Override
@@ -46,6 +45,6 @@ public class MmoeditCommand extends ExperienceCommand {
 
     @Override
     protected void handlePlayerMessageSkill() {
-        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", SkillUtils.getSkillName(skill), value));
+        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getSkillName(), value));
     }
 }

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java

@@ -12,7 +12,6 @@ import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class SkillresetCommand extends ExperienceCommand {
     private CommandSender sender;
@@ -117,6 +116,6 @@ public class SkillresetCommand extends ExperienceCommand {
 
     @Override
     protected void handlePlayerMessageSkill() {
-        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", SkillUtils.getSkillName(skill)));
+        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getSkillName()));
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java

@@ -50,7 +50,7 @@ public class HardcoreCommand extends HardcoreModeCommand {
 
     private void toggle(boolean enable) {
         if (skill.equalsIgnoreCase("ALL")) {
-            for (SkillType skillType : SkillType.nonChildSkills()) {
+            for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
                 skillType.setHardcoreStatLossEnabled(enable);
             }
         }

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java

@@ -50,7 +50,7 @@ public class VampirismCommand extends HardcoreModeCommand {
 
     private void toggle(boolean enable) {
         if (skill.equalsIgnoreCase("ALL")) {
-            for (SkillType skillType : SkillType.nonChildSkills()) {
+            for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
                 skillType.setHardcoreVampirismEnabled(enable);
             }
         }

+ 10 - 12
src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java

@@ -52,22 +52,20 @@ public class InspectCommand implements TabExecutor {
                     sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", playerName));
 
                     sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering"));
-                    CommandUtils.displaySkill(sender, profile, SkillType.EXCAVATION);
-                    CommandUtils.displaySkill(sender, profile, SkillType.FISHING);
-                    CommandUtils.displaySkill(sender, profile, SkillType.HERBALISM);
-                    CommandUtils.displaySkill(sender, profile, SkillType.MINING);
-                    CommandUtils.displaySkill(sender, profile, SkillType.WOODCUTTING);
+                    for (SkillType skill : SkillType.GATHERING_SKILLS) {
+                        sender.sendMessage(CommandUtils.displaySkill(profile, skill));
+                    }
 
                     sender.sendMessage(LocaleLoader.getString("Stats.Header.Combat"));
-                    CommandUtils.displaySkill(sender, profile, SkillType.AXES);
-                    CommandUtils.displaySkill(sender, profile, SkillType.ARCHERY);
-                    CommandUtils.displaySkill(sender, profile, SkillType.SWORDS);
-                    CommandUtils.displaySkill(sender, profile, SkillType.TAMING);
-                    CommandUtils.displaySkill(sender, profile, SkillType.UNARMED);
+                    for (SkillType skill : SkillType.COMBAT_SKILLS) {
+                        sender.sendMessage(CommandUtils.displaySkill(profile, skill));
+                    }
 
                     sender.sendMessage(LocaleLoader.getString("Stats.Header.Misc"));
-                    CommandUtils.displaySkill(sender, profile, SkillType.ACROBATICS);
-                    CommandUtils.displaySkill(sender, profile, SkillType.REPAIR);
+                    for (SkillType skill : SkillType.MISC_SKILLS) {
+                        sender.sendMessage(CommandUtils.displaySkill(profile, skill));
+                    }
+
                 }
                 else {
                     Player target = mcMMOPlayer.getPlayer();

+ 2 - 3
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -23,7 +23,6 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.gmail.nossr50.util.skills.PerksUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 import com.google.common.collect.ImmutableList;
 
@@ -46,7 +45,7 @@ public abstract class SkillCommand implements TabExecutor {
 
     public SkillCommand(SkillType skill) {
         this.skill = skill;
-        skillName = SkillUtils.getSkillName(skill);
+        skillName = skill.getSkillName();
         skillGuideCommand = new SkillGuideCommand(skill);
     }
 
@@ -91,7 +90,7 @@ public abstract class SkillCommand implements TabExecutor {
                     Set<SkillType> parents = FamilyTree.getParents(skill);
 
                     for (SkillType parent : parents) {
-                        player.sendMessage(SkillUtils.getSkillName(parent) + " - " + LocaleLoader.getString("Effects.Level", profile.getSkillLevel(parent), profile.getSkillXpLevel(parent), profile.getXpToLevel(parent)));
+                        player.sendMessage(parent.getSkillName() + " - " + LocaleLoader.getString("Effects.Level", profile.getSkillLevel(parent), profile.getSkillXpLevel(parent), profile.getXpToLevel(parent)));
                     }
                 }
 

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java

@@ -10,7 +10,6 @@ import org.bukkit.command.CommandSender;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.StringUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class SkillGuideCommand implements CommandExecutor {
     private String header;
@@ -19,7 +18,7 @@ public class SkillGuideCommand implements CommandExecutor {
     private String invalidPage;
 
     public SkillGuideCommand(SkillType skillType) {
-        header = LocaleLoader.getString("Guides.Header", SkillUtils.getSkillName(skillType));
+        header = LocaleLoader.getString("Guides.Header", skillType.getSkillName());
         guide = getGuide(skillType);
 
         invalidPage = LocaleLoader.getString("Guides.Page.Invalid");

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

@@ -299,7 +299,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
 
         Map<String, Integer> skills = new HashMap<String, Integer>();
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             skills.put(skill.name(), getPlayerRank(playerName, playerStatHash.get(skill)));
         }
 

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

@@ -237,7 +237,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
             ResultSet resultSet;
 
             try {
-                for (SkillType skillType : SkillType.nonChildSkills()) {
+                for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
                     String skillName = skillType.name().toLowerCase();
                     String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " +
                                  "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +

+ 147 - 2
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -9,10 +9,13 @@ import org.bukkit.GameMode;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.Server;
+import org.bukkit.Sound;
 import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
 import org.bukkit.scheduler.BukkitRunnable;
 
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.datatypes.mods.CustomTool;
@@ -25,6 +28,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.ToolLowerTask;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager;
 import com.gmail.nossr50.skills.archery.ArcheryManager;
@@ -41,9 +45,12 @@ import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
+import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.ModUtils;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.StringUtils;
+import com.gmail.nossr50.util.skills.ParticleEffectUtils;
 import com.gmail.nossr50.util.skills.PerksUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 
@@ -514,7 +521,7 @@ public class McMMOPlayer {
     public int getPowerLevel() {
         int powerLevel = 0;
 
-        for (SkillType type : SkillType.nonChildSkills()) {
+        for (SkillType type : SkillType.NON_CHILD_SKILLS) {
             if (Permissions.skillEnabled(player, type)) {
                 powerLevel += profile.getSkillLevel(type);
             }
@@ -597,7 +604,42 @@ public class McMMOPlayer {
         profile.setSkillXpLevel(skillType, profile.getSkillXpLevelRaw(skillType) + event.getRawXpGained());
 
         isUsingUnarmed = (skillType == SkillType.UNARMED);
-        SkillUtils.xpCheckSkill(skillType, player, profile);
+        checkXp(skillType);
+    }
+
+    /**
+     * Check the XP of a skill.
+     *
+     * @param skillType The skill to check
+     */
+    private void checkXp(SkillType skillType) {
+        int levelsGained = 0;
+        float xpRemoved = 0;
+
+        if (profile.getSkillXpLevelRaw(skillType) >= profile.getXpToLevel(skillType)) {
+            while (profile.getSkillXpLevelRaw(skillType) >= profile.getXpToLevel(skillType)) {
+                if ((skillType.getMaxLevel() >= profile.getSkillLevel(skillType) + 1) && (Config.getInstance().getPowerLevelCap() >= getPowerLevel() + 1)) {
+                    int xp = profile.getXpToLevel(skillType);
+                    xpRemoved += xp;
+
+                    profile.removeXp(skillType, xp);
+                    levelsGained++;
+                    profile.skillUp(skillType, 1);
+                }
+                else {
+                    profile.addLevels(skillType, 0);
+                }
+            }
+
+            if (EventUtils.callLevelUpEvent(player, skillType, levelsGained).isCancelled()) {
+                profile.modifySkill(skillType, profile.getSkillLevel(skillType) - levelsGained);
+                profile.setSkillXpLevel(skillType, profile.getSkillXpLevelRaw(skillType) + xpRemoved);
+                return;
+            }
+
+            player.playSound(player.getLocation(), Sound.LEVEL_UP, Misc.LEVELUP_VOLUME, Misc.LEVELUP_PITCH);
+            player.sendMessage(LocaleLoader.getString(StringUtils.getCapitalized(skillType.toString()) + ".Skillup", levelsGained, profile.getSkillLevel(skillType)));
+        }
     }
 
     /*
@@ -782,4 +824,107 @@ public class McMMOPlayer {
             player.sendMessage(LocaleLoader.getString("Party.Forbidden"));
         }
     }
+
+    /**
+     * Check to see if an ability can be activated.
+     *
+     * @param skill The skill the ability is based on
+     */
+    public void checkAbilityActivation(SkillType skill) {
+        ToolType tool = skill.getTool();
+        AbilityType ability = skill.getAbility();
+
+        setToolPreparationMode(tool, false);
+
+        if (!getAbilityMode(ability)) {
+            return;
+        }
+
+        int timeRemaining = SkillUtils.calculateTimeLeft(profile.getSkillDATS(ability) * Misc.TIME_CONVERSION_FACTOR, ability.getCooldown(), player);
+
+        if (timeRemaining > 0) {
+            /*
+             * Axes and Woodcutting are odd because they share the same tool.
+             * We show them the too tired message when they take action.
+             */
+            if (skill == SkillType.WOODCUTTING || skill == SkillType.AXES) {
+                player.sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));
+            }
+
+            return;
+        }
+
+        if (EventUtils.callPlayerAbilityActivateEvent(player, skill).isCancelled()) {
+            return;
+        }
+
+        int ticks = PerksUtils.handleActivationPerks(player, 2 + (profile.getSkillLevel(skill) / AdvancedConfig.getInstance().getAbilityLength()), ability.getMaxLength());
+
+        // Notify people that ability has been activated
+        ParticleEffectUtils.playAbilityEnabledEffect(player);
+
+        if (useChatNotifications()) {
+            player.sendMessage(ability.getAbilityOn());
+        }
+
+        SkillUtils.sendSkillMessage(player, ability.getAbilityPlayer(player));
+
+        // Enable the ability
+        profile.setSkillDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR));
+        setAbilityMode(ability, true);
+
+        if (ability == AbilityType.SUPER_BREAKER || ability == AbilityType.GIGA_DRILL_BREAKER) {
+            SkillUtils.handleAbilitySpeedIncrease(player);
+        }
+
+        new AbilityDisableTask(this, ability).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR);
+    }
+
+    public void processAbilityActivation(SkillType skill) {
+        if (Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) {
+            return;
+        }
+
+        ItemStack inHand = player.getItemInHand();
+
+        if (ModUtils.isCustomTool(inHand) && !ModUtils.getToolFromItemStack(inHand).isAbilityEnabled()) {
+            return;
+        }
+
+        if (!getAbilityUse()) {
+            return;
+        }
+
+        for (AbilityType abilityType : AbilityType.values()) {
+            if (getAbilityMode(abilityType)) {
+                return;
+            }
+        }
+
+        AbilityType ability = skill.getAbility();
+        ToolType tool = skill.getTool();
+
+        /*
+         * Woodcutting & Axes need to be treated differently.
+         * Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action
+         */
+        if (ability.getPermissions(player) && tool.inHand(inHand) && !getToolPreparationMode(tool)) {
+            if (skill != SkillType.WOODCUTTING && skill != SkillType.AXES) {
+                int timeRemaining = SkillUtils.calculateTimeLeft(profile.getSkillDATS(ability) * Misc.TIME_CONVERSION_FACTOR, ability.getCooldown(), player);
+
+                if (!getAbilityMode(ability) && timeRemaining > 0) {
+                    player.sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));
+                    return;
+                }
+            }
+
+            if (Config.getInstance().getAbilityMessagesEnabled()) {
+                player.sendMessage(tool.getRaiseTool());
+            }
+
+            setToolPreparationATS(tool, System.currentTimeMillis());
+            setToolPreparationMode(tool, true);
+            new ToolLowerTask(this, tool).runTaskLaterAsynchronously(mcMMO.p, 4 * Misc.TICK_CONVERSION_FACTOR);
+        }
+    }
 }

+ 2 - 6
src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java

@@ -39,7 +39,7 @@ public class PlayerProfile {
             skillsDATS.put(abilityType, 0);
         }
 
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             skills.put(skillType, 0);
             skillsXp.put(skillType, 0F);
         }
@@ -152,11 +152,7 @@ public class PlayerProfile {
      */
 
     public int getSkillLevel(SkillType skillType) {
-        if (skillType.isChildSkill()) {
-            return getChildSkillLevel(skillType);
-        }
-
-        return skills.get(skillType);
+        return skillType.isChildSkill() ? getChildSkillLevel(skillType) : skills.get(skillType);
     }
 
     public float getSkillXpLevelRaw(SkillType skillType) {

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

@@ -1,12 +1,14 @@
 package com.gmail.nossr50.datatypes.skills;
 
 import org.bukkit.Material;
+import org.bukkit.block.Block;
 import org.bukkit.block.BlockState;
 import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.BlockUtils;
+import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.StringUtils;
 
@@ -220,4 +222,23 @@ public enum AbilityType {
                 return false;
         }
     }
+
+    /**
+     * Check to see if ability should be triggered.
+     *
+     * @param player The player using the ability
+     * @param block The block modified by the ability
+     * @return true if the ability should activate, false otherwise
+     */
+    public boolean triggerCheck(Player player, Block block) {
+        switch (this) {
+            case BERSERK:
+            case BLOCK_CRACKER:
+            case LEAF_BLOWER:
+                return blockCheck(block.getState()) && EventUtils.simulateBlockBreak(block, player, true);
+
+            default:
+                return false;
+        }
+    }
 }

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

@@ -25,7 +25,6 @@ import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
 import com.gmail.nossr50.util.StringUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 import com.google.common.collect.ImmutableList;
 
@@ -51,15 +50,34 @@ public enum SkillType {
 
     public static final List<String> SKILL_NAMES;
 
+    public static final List<SkillType> CHILD_SKILLS;
+    public static final List<SkillType> NON_CHILD_SKILLS;
+
+    public static final List<SkillType> COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED);
+    public static final List<SkillType> GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING);
+    public static final List<SkillType> MISC_SKILLS = ImmutableList.of(ACROBATICS, REPAIR, SMELTING);
+
     static {
+        List<SkillType> childSkills = new ArrayList<SkillType>();
+        List<SkillType> nonChildSkills = new ArrayList<SkillType>();
         ArrayList<String> names = new ArrayList<String>();
 
         for (SkillType skill : values()) {
-            names.add(SkillUtils.getSkillName(skill));
+            if (skill.isChildSkill()) {
+                childSkills.add(skill);
+            }
+            else {
+                nonChildSkills.add(skill);
+            }
+
+            names.add(skill.getSkillName());
         }
 
         Collections.sort(names);
         SKILL_NAMES = ImmutableList.copyOf(names);
+
+        CHILD_SKILLS = ImmutableList.copyOf(childSkills);
+        NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills);
     }
 
     private SkillType(Class<? extends SkillManager> managerClass, Color runescapeColor) {
@@ -151,33 +169,14 @@ public enum SkillType {
     // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them
     public boolean isChildSkill() {
         switch (this) {
-        case SMELTING:
-            return true;
+            case SMELTING:
+                return true;
 
-        default:
-            return false;
+            default:
+                return false;
         }
     }
 
-    public static SkillType[] nonChildSkills() {
-        return new SkillType[] {SkillType.ACROBATICS,
-                SkillType.ARCHERY,
-                SkillType.AXES,
-                SkillType.EXCAVATION,
-                SkillType.FISHING,
-                SkillType.HERBALISM,
-                SkillType.MINING,
-                SkillType.REPAIR,
-                SkillType.SWORDS,
-                SkillType.TAMING,
-                SkillType.UNARMED,
-                SkillType.WOODCUTTING };
-    }
-
-    public static SkillType[] childSkills() {
-        return new SkillType[] { SkillType.SMELTING };
-    }
-
     public Color getRunescapeModeColor() {
         return runescapeColor;
     }
@@ -191,4 +190,8 @@ public enum SkillType {
 
         return null;
     }
+
+    public String getSkillName() {
+        return Config.getInstance().getLocale().equalsIgnoreCase("en_US") ? StringUtils.getCapitalized(this.toString()) : StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName"));
+    }
 }

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

@@ -149,7 +149,7 @@ public class BlockListener implements Listener {
 
             /* Green Terra */
             if (herbalismManager.canActivateAbility()) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.HERBALISM);
+                mcMMOPlayer.checkAbilityActivation(SkillType.HERBALISM);
             }
 
             /*
@@ -280,19 +280,19 @@ public class BlockListener implements Listener {
             }
 
             if (mcMMOPlayer.getToolPreparationMode(ToolType.HOE) && ItemUtils.isHoe(heldItem) && (BlockUtils.affectedByGreenTerra(blockState) || BlockUtils.canMakeMossy(blockState)) && Permissions.greenTerra(player)) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.HERBALISM);
+                mcMMOPlayer.checkAbilityActivation(SkillType.HERBALISM);
             }
             else if (mcMMOPlayer.getToolPreparationMode(ToolType.AXE) && ItemUtils.isAxe(heldItem) && BlockUtils.isLog(blockState) && Permissions.treeFeller(player)) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.WOODCUTTING);
+                mcMMOPlayer.checkAbilityActivation(SkillType.WOODCUTTING);
             }
             else if (mcMMOPlayer.getToolPreparationMode(ToolType.PICKAXE) && ItemUtils.isPickaxe(heldItem) && BlockUtils.affectedBySuperBreaker(blockState) && Permissions.superBreaker(player)) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.MINING);
+                mcMMOPlayer.checkAbilityActivation(SkillType.MINING);
             }
             else if (mcMMOPlayer.getToolPreparationMode(ToolType.SHOVEL) && ItemUtils.isShovel(heldItem) && BlockUtils.affectedByGigaDrillBreaker(blockState) && Permissions.gigaDrillBreaker(player)) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.EXCAVATION);
+                mcMMOPlayer.checkAbilityActivation(SkillType.EXCAVATION);
             }
             else if (mcMMOPlayer.getToolPreparationMode(ToolType.FISTS) && heldItem.getType() == Material.AIR && (BlockUtils.affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW || BlockUtils.affectedByBlockCracker(blockState) && Permissions.berserk(player))) {
-                SkillUtils.abilityCheck(mcMMOPlayer, SkillType.UNARMED);
+                mcMMOPlayer.checkAbilityActivation(SkillType.UNARMED);
             }
         }
 
@@ -339,17 +339,17 @@ public class BlockListener implements Listener {
             }
         }
         else if (mcMMOPlayer.getAbilityMode(AbilityType.BERSERK) && heldItem.getType() == Material.AIR) {
-            if (SkillUtils.triggerCheck(player, block, AbilityType.BERSERK)) {
+            if (AbilityType.BERSERK.triggerCheck(player, block)) {
                 event.setInstaBreak(true);
                 player.playSound(block.getLocation(), Sound.ITEM_PICKUP, Misc.POP_VOLUME, Misc.getPopPitch());
             }
-            else if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker() && SkillUtils.triggerCheck(player, block, AbilityType.BLOCK_CRACKER)) {
+            else if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker() && AbilityType.BLOCK_CRACKER.triggerCheck(player, block)) {
                 if (mcMMOPlayer.getUnarmedManager().blockCrackerCheck(blockState)) {
                     blockState.update();
                 }
             }
         }
-        else if (mcMMOPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) && SkillUtils.triggerCheck(player, block, AbilityType.LEAF_BLOWER)) {
+        else if (mcMMOPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) && AbilityType.LEAF_BLOWER.triggerCheck(player, block)) {
             event.setInstaBreak(true);
             player.playSound(blockState.getLocation(), Sound.ITEM_PICKUP, Misc.POP_VOLUME, Misc.getPopPitch());
         }

+ 18 - 17
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -49,6 +49,7 @@ import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.Unarmed;
 import com.gmail.nossr50.util.BlockUtils;
 import com.gmail.nossr50.util.ChimaeraWing;
+import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.HardcoreManager;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
@@ -514,15 +515,15 @@ public class PlayerListener implements Listener {
                 if (BlockUtils.canActivateAbilities(blockState)) {
                     if (Config.getInstance().getAbilitiesEnabled()) {
                         if (BlockUtils.canActivateHerbalism(blockState)) {
-                            SkillUtils.activationCheck(player, SkillType.HERBALISM);
+                            mcMMOPlayer.processAbilityActivation(SkillType.HERBALISM);
                         }
 
-                        SkillUtils.activationCheck(player, SkillType.AXES);
-                        SkillUtils.activationCheck(player, SkillType.EXCAVATION);
-                        SkillUtils.activationCheck(player, SkillType.MINING);
-                        SkillUtils.activationCheck(player, SkillType.SWORDS);
-                        SkillUtils.activationCheck(player, SkillType.UNARMED);
-                        SkillUtils.activationCheck(player, SkillType.WOODCUTTING);
+                        mcMMOPlayer.processAbilityActivation(SkillType.AXES);
+                        mcMMOPlayer.processAbilityActivation(SkillType.EXCAVATION);
+                        mcMMOPlayer.processAbilityActivation(SkillType.MINING);
+                        mcMMOPlayer.processAbilityActivation(SkillType.SWORDS);
+                        mcMMOPlayer.processAbilityActivation(SkillType.UNARMED);
+                        mcMMOPlayer.processAbilityActivation(SkillType.WOODCUTTING);
                     }
 
                     ChimaeraWing.activationCheck(player);
@@ -534,14 +535,14 @@ public class PlayerListener implements Listener {
                 if (herbalismManager.canGreenThumbBlock(blockState)) {
                     player.setItemInHand(new ItemStack(Material.SEEDS, heldItem.getAmount() - 1));
 
-                    if (herbalismManager.processGreenThumbBlocks(blockState) && SkillUtils.blockBreakSimulate(block, player, false)) {
+                    if (herbalismManager.processGreenThumbBlocks(blockState) && EventUtils.simulateBlockBreak(block, player, false)) {
                         blockState.update(true);
                     }
                 }
 
                 /* SHROOM THUMB CHECK */
                 else if (herbalismManager.canUseShroomThumb(blockState)) {
-                    if (herbalismManager.processShroomThumb(blockState) && SkillUtils.blockBreakSimulate(block, player, false)) {
+                    if (herbalismManager.processShroomThumb(blockState) && EventUtils.simulateBlockBreak(block, player, false)) {
                         blockState.update(true);
                     }
                 }
@@ -551,13 +552,13 @@ public class PlayerListener implements Listener {
 
                 /* ACTIVATION CHECKS */
                 if (Config.getInstance().getAbilitiesEnabled()) {
-                    SkillUtils.activationCheck(player, SkillType.AXES);
-                    SkillUtils.activationCheck(player, SkillType.EXCAVATION);
-                    SkillUtils.activationCheck(player, SkillType.HERBALISM);
-                    SkillUtils.activationCheck(player, SkillType.MINING);
-                    SkillUtils.activationCheck(player, SkillType.SWORDS);
-                    SkillUtils.activationCheck(player, SkillType.UNARMED);
-                    SkillUtils.activationCheck(player, SkillType.WOODCUTTING);
+                    mcMMOPlayer.processAbilityActivation(SkillType.AXES);
+                    mcMMOPlayer.processAbilityActivation(SkillType.EXCAVATION);
+                    mcMMOPlayer.processAbilityActivation(SkillType.HERBALISM);
+                    mcMMOPlayer.processAbilityActivation(SkillType.MINING);
+                    mcMMOPlayer.processAbilityActivation(SkillType.SWORDS);
+                    mcMMOPlayer.processAbilityActivation(SkillType.UNARMED);
+                    mcMMOPlayer.processAbilityActivation(SkillType.WOODCUTTING);
                 }
 
                 /* ITEM CHECKS */
@@ -659,7 +660,7 @@ public class PlayerListener implements Listener {
             // Do these ACTUALLY have to be lower case to work properly?
             for (SkillType skill : SkillType.values()) {
                 String skillName = skill.toString().toLowerCase();
-                String localizedName = SkillUtils.getSkillName(skill).toLowerCase();
+                String localizedName = skill.getSkillName().toLowerCase();
 
                 if (lowerCaseCommand.equals(localizedName)) {
                     event.setMessage(message.replace(command, skillName));

+ 2 - 3
src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java

@@ -10,7 +10,6 @@ import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class McrankCommandDisplayTask extends BukkitRunnable {
     private final Map<String, Integer> skills;
@@ -31,13 +30,13 @@ public class McrankCommandDisplayTask extends BukkitRunnable {
         sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading"));
         sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName));
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             if (player != null && !Permissions.skillEnabled(player, skill)) {
                 continue;
             }
 
             rank = skills.get(skill.name());
-            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", SkillUtils.getSkillName(skill), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
+            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getSkillName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
         }
 
         rank = skills.get("ALL");

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java

@@ -52,7 +52,7 @@ public class FormulaConversionTask extends BukkitRunnable {
     private void editValues(PlayerProfile profile) {
         mcMMO.p.debug("========================================================================");
         mcMMO.p.debug("Conversion report for " + profile.getPlayerName() + ":");
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             int oldLevel = profile.getSkillLevel(skillType);
             int oldXPLevel = profile.getSkillXpLevel(skillType);
             int totalOldXP = mcMMO.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel);

+ 1 - 1
src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java

@@ -20,7 +20,7 @@ public class ChildConfig extends AutoUpdateConfigLoader {
 
         FamilyTree.clearRegistrations(); // when reloading, need to clear statics
 
-        for (SkillType skill : SkillType.childSkills()) {
+        for (SkillType skill : SkillType.CHILD_SKILLS) {
             plugin.debug("Finding parents of " + skill.name());
 
             EnumSet<SkillType> parentSkills = EnumSet.noneOf(SkillType.class);

+ 2 - 1
src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java

@@ -22,6 +22,7 @@ import com.gmail.nossr50.runnables.skills.AbilityCooldownTask;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.mining.BlastMining.Tier;
 import com.gmail.nossr50.util.BlockUtils;
+import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.ModUtils;
 import com.gmail.nossr50.util.Permissions;
@@ -95,7 +96,7 @@ public class MiningManager extends SkillManager {
         Player player = getPlayer();
         Block targetBlock = player.getTargetBlock(BlockUtils.getTransparentBlocks(), BlastMining.MAXIMUM_REMOTE_DETONATION_DISTANCE);
 
-        if (targetBlock.getType() != Material.TNT || !SkillUtils.blockBreakSimulate(targetBlock, player, true) || !blastMiningCooldownOver()) {
+        if (targetBlock.getType() != Material.TNT || !EventUtils.simulateBlockBreak(targetBlock, player, true) || !blastMiningCooldownOver()) {
             return;
         }
 

+ 2 - 1
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java

@@ -18,6 +18,7 @@ import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.woodcutting.Woodcutting.ExperienceGainMethod;
+import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.ModUtils;
@@ -129,7 +130,7 @@ public class WoodcuttingManager extends SkillManager {
         for (BlockState blockState : treeFellerBlocks) {
             Block block = blockState.getBlock();
 
-            if (!SkillUtils.blockBreakSimulate(block, player, true)) {
+            if (!EventUtils.simulateBlockBreak(block, player, true)) {
                 break; // TODO: Shouldn't we use continue instead?
             }
 

+ 62 - 0
src/main/java/com/gmail/nossr50/util/EventUtils.java

@@ -0,0 +1,62 @@
+package com.gmail.nossr50.util;
+
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.PluginManager;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent;
+import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
+import com.gmail.nossr50.events.fake.FakeBlockDamageEvent;
+import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
+import com.gmail.nossr50.events.skills.abilities.McMMOPlayerAbilityActivateEvent;
+
+public class EventUtils {
+    public static McMMOPlayerAbilityActivateEvent callPlayerAbilityActivateEvent(Player player, SkillType skill) {
+        McMMOPlayerAbilityActivateEvent event = new McMMOPlayerAbilityActivateEvent(player, skill);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        return event;
+    }
+
+    public static FakePlayerAnimationEvent callFakeArmSwingEvent(Player player) {
+        FakePlayerAnimationEvent event = new FakePlayerAnimationEvent(player);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        return event;
+    }
+
+    public static McMMOPlayerLevelUpEvent callLevelUpEvent(Player player, SkillType skill, int levelsGained) {
+        McMMOPlayerLevelUpEvent event = new McMMOPlayerLevelUpEvent(player, skill, levelsGained);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        return event;
+    }
+
+    /**
+     * Simulate a block break event.
+     *
+     * @param block The block to break
+     * @param player The player breaking the block
+     * @param shouldArmSwing true if an armswing event should be fired, false otherwise
+     * @return true if the event wasn't cancelled, false otherwise
+     */
+    public static boolean simulateBlockBreak(Block block, Player player, boolean shouldArmSwing) {
+        PluginManager pluginManager = mcMMO.p.getServer().getPluginManager();
+
+        // Support for NoCheat
+        if (shouldArmSwing) {
+            callFakeArmSwingEvent(player);
+        }
+
+        FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block, player.getItemInHand(), true);
+        pluginManager.callEvent(damageEvent);
+
+        FakeBlockBreakEvent breakEvent = new FakeBlockBreakEvent(block, player);
+        pluginManager.callEvent(breakEvent);
+
+        return !damageEvent.isCancelled() && !breakEvent.isCancelled();
+    }
+}
+

+ 4 - 4
src/main/java/com/gmail/nossr50/util/HardcoreManager.java

@@ -26,7 +26,7 @@ public final class HardcoreManager {
         PlayerProfile playerProfile = UserManager.getPlayer(player).getProfile();
         int totalLost = 0;
 
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             int playerSkillLevel = playerProfile.getSkillLevel(skillType);
 
             if (playerSkillLevel <= 0) {
@@ -56,7 +56,7 @@ public final class HardcoreManager {
         PlayerProfile victimProfile = UserManager.getPlayer(victim).getProfile();
         int totalStolen = 0;
 
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             int killerSkillLevel = killerProfile.getSkillLevel(skillType);
             int victimSkillLevel = victimProfile.getSkillLevel(skillType);
 
@@ -89,7 +89,7 @@ public final class HardcoreManager {
     public static boolean isStatLossEnabled() {
         boolean enabled = false;
 
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             if (skillType.getHardcoreStatLossEnabled()) {
                 enabled = true;
                 break;
@@ -107,7 +107,7 @@ public final class HardcoreManager {
     public static boolean isVampirismEnabled() {
         boolean enabled = false;
 
-        for (SkillType skillType : SkillType.nonChildSkills()) {
+        for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
             if (skillType.getHardcoreVampirismEnabled()) {
                 enabled = true;
                 break;

+ 1 - 2
src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java

@@ -50,7 +50,6 @@ import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.StringUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public final class CommandRegistrationManager {
     private CommandRegistrationManager() {};
@@ -60,7 +59,7 @@ public final class CommandRegistrationManager {
     private static void registerSkillCommands() {
         for (SkillType skill : SkillType.values()) {
             String commandName = skill.toString().toLowerCase();
-            String localizedName = SkillUtils.getSkillName(skill).toLowerCase();
+            String localizedName = skill.getSkillName().toLowerCase();
 
             PluginCommand command;
 

+ 27 - 32
src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.util.commands;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.bukkit.OfflinePlayer;
@@ -157,16 +158,7 @@ public final class CommandUtils {
      * @param display The sender to display stats to
      */
     public static void printGatheringSkills(Player inspect, CommandSender display) {
-        if (SkillUtils.hasGatheringSkills(inspect)) {
-            PlayerProfile profile = UserManager.getPlayer(inspect).getProfile();
-
-            display.sendMessage(LocaleLoader.getString("Stats.Header.Gathering"));
-            displaySkill(inspect, profile, SkillType.EXCAVATION, display);
-            displaySkill(inspect, profile, SkillType.FISHING, display);
-            displaySkill(inspect, profile, SkillType.HERBALISM, display);
-            displaySkill(inspect, profile, SkillType.MINING, display);
-            displaySkill(inspect, profile, SkillType.WOODCUTTING, display);
-        }
+        printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), SkillType.GATHERING_SKILLS);
     }
 
     public static void printGatheringSkills(Player player) {
@@ -180,16 +172,7 @@ public final class CommandUtils {
      * @param display The sender to display stats to
      */
     public static void printCombatSkills(Player inspect, CommandSender display) {
-        if (SkillUtils.hasCombatSkills(inspect)) {
-            PlayerProfile profile = UserManager.getPlayer(inspect).getProfile();
-
-            display.sendMessage(LocaleLoader.getString("Stats.Header.Combat"));
-            displaySkill(inspect, profile, SkillType.AXES, display);
-            displaySkill(inspect, profile, SkillType.ARCHERY, display);
-            displaySkill(inspect, profile, SkillType.SWORDS, display);
-            displaySkill(inspect, profile, SkillType.TAMING, display);
-            displaySkill(inspect, profile, SkillType.UNARMED, display);
-        }
+        printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), SkillType.COMBAT_SKILLS);
     }
 
     public static void printCombatSkills(Player player) {
@@ -203,26 +186,38 @@ public final class CommandUtils {
      * @param display The sender to display stats to
      */
     public static void printMiscSkills(Player inspect, CommandSender display) {
-        if (SkillUtils.hasMiscSkills(inspect)) {
-            PlayerProfile profile = UserManager.getPlayer(inspect).getProfile();
-
-            display.sendMessage(LocaleLoader.getString("Stats.Header.Misc"));
-            displaySkill(inspect, profile, SkillType.ACROBATICS, display);
-            displaySkill(inspect, profile, SkillType.REPAIR, display);
-        }
+        printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), SkillType.MISC_SKILLS);
     }
 
     public static void printMiscSkills(Player player) {
         printMiscSkills(player, player);
     }
 
-    private static void displaySkill(Player player, PlayerProfile profile, SkillType skill, CommandSender display) {
-        if (Permissions.skillEnabled(player, skill)) {
-            displaySkill(display, profile, skill);
+    public static String displaySkill(PlayerProfile profile, SkillType skill) {
+        if (skill.isChildSkill()) {
+            return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener"), profile.getSkillLevel(skill));
         }
+
+        return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener"), profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill));
     }
 
-    public static void displaySkill(CommandSender sender, PlayerProfile profile, SkillType skill) {
-        sender.sendMessage(LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener"), profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)));
+    private static void printGroupedSkillData(Player inspect, CommandSender display, String header, List<SkillType> skillGroup) {
+        PlayerProfile profile = UserManager.getPlayer(inspect).getProfile();
+
+        List<String> displayData = new ArrayList<String>();
+        displayData.add(header);
+
+        for (SkillType skill : skillGroup) {
+            if (Permissions.skillEnabled(inspect, skill)) {
+                displayData.add(displaySkill(profile, skill));
+            }
+        }
+
+        int size = displayData.size();
+
+        if (size > 1) {
+            display.sendMessage(displayData.toArray(new String[size]));
+        }
     }
+
 }

+ 13 - 14
src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java

@@ -23,7 +23,6 @@ import com.gmail.nossr50.runnables.scoreboards.ScoreboardChangeTask;
 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.SkillUtils;
 
 public class ScoreboardManager {
     private static final Map<String, Scoreboard> PLAYER_SCOREBOARDS = new HashMap<String, Scoreboard>();
@@ -80,10 +79,10 @@ public class ScoreboardManager {
         Player player = mcMMOPlayer.getPlayer();
         Scoreboard oldScoreboard = player.getScoreboard();
         Scoreboard newScoreboard = PLAYER_SCOREBOARDS.get(player.getName());
-        Objective objective = newScoreboard.getObjective(SkillUtils.getSkillName(skill));
+        Objective objective = newScoreboard.getObjective(skill.getSkillName());
 
         if (objective == null) {
-            objective = newScoreboard.registerNewObjective(SkillUtils.getSkillName(skill), "dummy");
+            objective = newScoreboard.registerNewObjective(skill.getSkillName(), "dummy");
         }
 
         updatePlayerSkillScores(mcMMOPlayer.getProfile(), skill, objective);
@@ -165,7 +164,7 @@ public class ScoreboardManager {
         }
 
         Objective newObjective = GLOBAL_STATS_SCOREBOARD.registerNewObjective(skillName, "dummy");
-        newObjective.setDisplayName(ChatColor.GOLD + (skillName.equalsIgnoreCase("all") ? POWER_LEVEL : SkillUtils.getSkillName(SkillType.getSkill(skillName))));
+        newObjective.setDisplayName(ChatColor.GOLD + (skillName.equalsIgnoreCase("all") ? POWER_LEVEL : SkillType.getSkill(skillName).getSkillName()));
 
         updateGlobalStatsScores(player, newObjective, skillName, pageNumber);
         changeScoreboard(player, oldScoreboard, GLOBAL_STATS_SCOREBOARD, Config.getInstance().getMctopScoreboardTime());
@@ -187,12 +186,12 @@ public class ScoreboardManager {
         PlayerProfile profile = mcMMOPlayer.getProfile();
         Server server = mcMMO.p.getServer();
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             if (!Permissions.skillEnabled(player, skill)) {
                 continue;
             }
 
-            objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(profile.getSkillLevel(skill));
+            objective.getScore(server.getOfflinePlayer(skill.getSkillName())).setScore(profile.getSkillLevel(skill));
         }
 
         objective.getScore(server.getOfflinePlayer(ChatColor.GOLD + POWER_LEVEL)).setScore(mcMMOPlayer.getPowerLevel());
@@ -206,7 +205,7 @@ public class ScoreboardManager {
 
         Map<String, Integer> skills = mcMMO.getDatabaseManager().readRank(playerName);
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             if (!Permissions.skillEnabled(player, skill)) {
                 continue;
             }
@@ -214,7 +213,7 @@ public class ScoreboardManager {
             rank = skills.get(skill.name());
 
             if (rank != null) {
-                objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(rank);
+                objective.getScore(server.getOfflinePlayer(skill.getSkillName())).setScore(rank);
             }
         }
 
@@ -233,11 +232,11 @@ public class ScoreboardManager {
 
         Map<String, Integer> skills = mcMMO.getDatabaseManager().readRank(targetName);
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             rank = skills.get(skill.name());
 
             if (rank != null) {
-                objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(rank);
+                objective.getScore(server.getOfflinePlayer(skill.getSkillName())).setScore(rank);
             }
         }
 
@@ -258,13 +257,13 @@ public class ScoreboardManager {
         int powerLevel = 0;
         int skillLevel;
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             if (!Permissions.skillEnabled(target, skill)) {
                 continue;
             }
 
             skillLevel = profile.getSkillLevel(skill);
-            objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(skillLevel);
+            objective.getScore(server.getOfflinePlayer(skill.getSkillName())).setScore(skillLevel);
             powerLevel += skillLevel;
         }
 
@@ -278,9 +277,9 @@ public class ScoreboardManager {
         int powerLevel = 0;
         int skillLevel;
 
-        for (SkillType skill : SkillType.nonChildSkills()) {
+        for (SkillType skill : SkillType.NON_CHILD_SKILLS) {
             skillLevel = targetProfile.getSkillLevel(skill);
-            objective.getScore(server.getOfflinePlayer(SkillUtils.getSkillName(skill))).setScore(skillLevel);
+            objective.getScore(server.getOfflinePlayer(skill.getSkillName())).setScore(skillLevel);
             powerLevel += skillLevel;
         }
 

+ 3 - 3
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -51,7 +51,7 @@ public final class CombatUtils {
         SwordsManager swordsManager = mcMMOPlayer.getSwordsManager();
 
         if (swordsManager.canActivateAbility()) {
-            SkillUtils.abilityCheck(mcMMOPlayer, SkillType.SWORDS);
+            mcMMOPlayer.checkAbilityActivation(SkillType.SWORDS);
         }
 
         if (swordsManager.canUseBleed()) {
@@ -73,7 +73,7 @@ public final class CombatUtils {
         AxesManager axesManager = mcMMOPlayer.getAxesManager();
 
         if (axesManager.canActivateAbility()) {
-            SkillUtils.abilityCheck(mcMMOPlayer, SkillType.AXES);
+            mcMMOPlayer.checkAbilityActivation(SkillType.AXES);
         }
 
         if (axesManager.canUseAxeMastery()) {
@@ -107,7 +107,7 @@ public final class CombatUtils {
         UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager();
 
         if (unarmedManager.canActivateAbility()) {
-            SkillUtils.abilityCheck(mcMMOPlayer, SkillType.UNARMED);
+            mcMMOPlayer.checkAbilityActivation(SkillType.UNARMED);
         }
 
         if (unarmedManager.canUseIronArm()) {

+ 41 - 350
src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java

@@ -3,39 +3,24 @@ package com.gmail.nossr50.util.skills;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.bukkit.Location;
 import org.bukkit.Material;
-import org.bukkit.Sound;
-import org.bukkit.block.Block;
 import org.bukkit.enchantments.Enchantment;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.PlayerInventory;
 import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.plugin.PluginManager;
 import org.bukkit.potion.PotionEffect;
 import org.bukkit.potion.PotionEffectType;
 
-import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.HiddenConfig;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.datatypes.player.PlayerProfile;
 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.events.experience.McMMOPlayerLevelUpEvent;
-import com.gmail.nossr50.events.fake.FakeBlockBreakEvent;
-import com.gmail.nossr50.events.fake.FakeBlockDamageEvent;
-import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
-import com.gmail.nossr50.events.skills.abilities.McMMOPlayerAbilityActivateEvent;
 import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.runnables.skills.AbilityDisableTask;
-import com.gmail.nossr50.runnables.skills.ToolLowerTask;
 import com.gmail.nossr50.util.ItemUtils;
 import com.gmail.nossr50.util.Misc;
-import com.gmail.nossr50.util.ModUtils;
-import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.StringUtils;
 import com.gmail.nossr50.util.player.UserManager;
 
@@ -78,108 +63,7 @@ public class SkillUtils {
      * @return true if the cooldown is expired
      */
     public static boolean cooldownExpired(long deactivatedTimeStamp, int cooldown) {
-        return (System.currentTimeMillis() >= (deactivatedTimeStamp + cooldown) * Misc.TIME_CONVERSION_FACTOR);
-    }
-
-    /**
-     * Process activating abilities & readying the tool.
-     *
-     * @param player The player using the ability
-     * @param skill The skill the ability is tied to
-     */
-    public static void activationCheck(Player player, SkillType skill) {
-        if (Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) {
-            return;
-        }
-
-        ItemStack inHand = player.getItemInHand();
-
-        if (ModUtils.isCustomTool(inHand) && !ModUtils.getToolFromItemStack(inHand).isAbilityEnabled()) {
-            return;
-        }
-
-        McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
-
-        if (!mcMMOPlayer.getAbilityUse()) {
-            return;
-        }
-
-        for (AbilityType abilityType : AbilityType.values()) {
-            if (mcMMOPlayer.getAbilityMode(abilityType)) {
-                return;
-            }
-        }
-
-        PlayerProfile playerProfile = mcMMOPlayer.getProfile();
-        AbilityType ability = skill.getAbility();
-        ToolType tool = skill.getTool();
-
-        /*
-         * Woodcutting & Axes need to be treated differently.
-         * Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action
-         */
-        if (ability.getPermissions(player) && tool.inHand(inHand) && !mcMMOPlayer.getToolPreparationMode(tool)) {
-            if (skill != SkillType.WOODCUTTING && skill != SkillType.AXES) {
-                int timeRemaining = calculateTimeLeft(playerProfile.getSkillDATS(ability) * Misc.TIME_CONVERSION_FACTOR, ability.getCooldown(), player);
-
-                if (!mcMMOPlayer.getAbilityMode(ability) && timeRemaining > 0) {
-                    player.sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));
-                    return;
-                }
-            }
-
-            if (Config.getInstance().getAbilityMessagesEnabled()) {
-                player.sendMessage(tool.getRaiseTool());
-            }
-
-            mcMMOPlayer.setToolPreparationATS(tool, System.currentTimeMillis());
-            mcMMOPlayer.setToolPreparationMode(tool, true);
-            new ToolLowerTask(mcMMOPlayer, tool).runTaskLaterAsynchronously(mcMMO.p, 4 * Misc.TICK_CONVERSION_FACTOR);
-        }
-    }
-
-    /**
-     * Check the XP of a skill.
-     *
-     * @param skillType The skill to check
-     * @param player The player whose skill to check
-     * @param profile The profile of the player whose skill to check
-     */
-    public static void xpCheckSkill(SkillType skillType, Player player, PlayerProfile profile) {
-        int levelsGained = 0;
-        float xpRemoved = 0;
-
-        if (profile.getSkillXpLevelRaw(skillType) >= profile.getXpToLevel(skillType)) {
-            McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
-
-            while (profile.getSkillXpLevelRaw(skillType) >= profile.getXpToLevel(skillType)) {
-                if ((skillType.getMaxLevel() >= profile.getSkillLevel(skillType) + 1) && (Config.getInstance().getPowerLevelCap() >= mcMMOPlayer.getPowerLevel() + 1)) {
-                    int xp = profile.getXpToLevel(skillType);
-                    xpRemoved += xp;
-
-                    profile.removeXp(skillType, xp);
-                    levelsGained++;
-                    profile.skillUp(skillType, 1);
-                }
-                else {
-                    profile.addLevels(skillType, 0);
-                }
-            }
-
-            McMMOPlayerLevelUpEvent eventToFire = new McMMOPlayerLevelUpEvent(player, skillType, levelsGained);
-            mcMMO.p.getServer().getPluginManager().callEvent(eventToFire);
-
-            if (eventToFire.isCancelled()) {
-                profile.modifySkill(skillType, profile.getSkillLevel(skillType) - levelsGained);
-                profile.setSkillXpLevel(skillType, profile.getSkillXpLevelRaw(skillType) + xpRemoved);
-                return;
-            }
-
-            String capitalized = StringUtils.getCapitalized(skillType.toString());
-
-            player.playSound(player.getLocation(), Sound.LEVEL_UP, Misc.LEVELUP_VOLUME, Misc.LEVELUP_PITCH);
-            player.sendMessage(LocaleLoader.getString(capitalized + ".Skillup", levelsGained, profile.getSkillLevel(skillType)));
-        }
+        return System.currentTimeMillis() >= (deactivatedTimeStamp + cooldown) * Misc.TIME_CONVERSION_FACTOR;
     }
 
     /**
@@ -189,174 +73,14 @@ public class SkillUtils {
      * @return true if this is a valid skill, false otherwise
      */
     public static boolean isSkill(String skillName) {
-        if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) {
-            return isLocalizedSkill(skillName);
-        }
-
-        return SkillType.getSkill(skillName) != null;
-    }
-
-    private static boolean isLocalizedSkill(String skillName) {
-        for (SkillType skill : SkillType.values()) {
-            if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".SkillName"))) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public static String getSkillName(SkillType skill) {
-        if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) {
-            return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".SkillName"));
-        }
-
-        return StringUtils.getCapitalized(skill.toString());
-    }
-
-    /**
-     * Check if the player has any combat skill permissions.
-     *
-     * @param player The player to check permissions for
-     * @return true if the player has combat skills, false otherwise
-     */
-    public static boolean hasCombatSkills(Player player) {
-        return Permissions.skillEnabled(player, SkillType.AXES)
-                || Permissions.skillEnabled(player, SkillType.ARCHERY)
-                || Permissions.skillEnabled(player, SkillType.SWORDS)
-                || Permissions.skillEnabled(player, SkillType.TAMING)
-                || Permissions.skillEnabled(player, SkillType.UNARMED);
-    }
-
-    /**
-     * Check if the player has any gathering skill permissions.
-     *
-     * @param player The player to check permissions for
-     * @return true if the player has gathering skills, false otherwise
-     */
-    public static boolean hasGatheringSkills(Player player) {
-        return Permissions.skillEnabled(player, SkillType.EXCAVATION)
-                || Permissions.skillEnabled(player, SkillType.FISHING)
-                || Permissions.skillEnabled(player, SkillType.HERBALISM)
-                || Permissions.skillEnabled(player, SkillType.MINING)
-                || Permissions.skillEnabled(player, SkillType.WOODCUTTING);
-    }
-
-    /**
-     * Check if the player has any misc skill permissions.
-     *
-     * @param player The player to check permissions for
-     * @return true if the player has misc skills, false otherwise
-     */
-    public static boolean hasMiscSkills(Player player) {
-        return Permissions.skillEnabled(player, SkillType.ACROBATICS)
-                || Permissions.skillEnabled(player, SkillType.SMELTING)
-                || Permissions.skillEnabled(player, SkillType.REPAIR);
-    }
-
-    /**
-     * Check to see if an ability can be activated.
-     *
-     * @param mcMMOPlayer The player activating the ability
-     * @param type The skill the ability is based on
-     */
-    public static void abilityCheck(McMMOPlayer mcMMOPlayer, SkillType type) {
-        ToolType tool = type.getTool();
-        AbilityType ability = type.getAbility();
-
-        mcMMOPlayer.setToolPreparationMode(tool, false);
-
-        Player player = mcMMOPlayer.getPlayer();
-        PlayerProfile playerProfile = mcMMOPlayer.getProfile();
-
-        int timeRemaining = calculateTimeLeft(playerProfile.getSkillDATS(ability) * Misc.TIME_CONVERSION_FACTOR, ability.getCooldown(), player);
-
-        /*
-         * Axes and Woodcutting are odd because they share the same tool.
-         * We show them the too tired message when they take action.
-         */
-        if (type == SkillType.WOODCUTTING || type == SkillType.AXES) {
-            if (!mcMMOPlayer.getAbilityMode(ability) && timeRemaining > 0) {
-                player.sendMessage(LocaleLoader.getString("Skills.TooTired", timeRemaining));
-                return;
-            }
-        }
-
-        if (!mcMMOPlayer.getAbilityMode(ability) && timeRemaining <= 0) {
-            McMMOPlayerAbilityActivateEvent event = new McMMOPlayerAbilityActivateEvent(player, type);
-            mcMMO.p.getServer().getPluginManager().callEvent(event);
-
-            if (event.isCancelled()) {
-                return;
-            }
-
-            int ticks = PerksUtils.handleActivationPerks(player, 2 + (playerProfile.getSkillLevel(type) / AdvancedConfig.getInstance().getAbilityLength()), ability.getMaxLength());
-
-            ParticleEffectUtils.playAbilityEnabledEffect(player);
-
-            if (mcMMOPlayer.useChatNotifications()) {
-                player.sendMessage(ability.getAbilityOn());
-            }
-
-            SkillUtils.sendSkillMessage(player, ability.getAbilityPlayer(player));
-
-            playerProfile.setSkillDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR));
-            mcMMOPlayer.setAbilityMode(ability, true);
-
-            if (ability == AbilityType.SUPER_BREAKER || ability == AbilityType.GIGA_DRILL_BREAKER) {
-                handleAbilitySpeedIncrease(player);
-            }
-
-            new AbilityDisableTask(mcMMOPlayer, ability).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR);
-        }
-    }
-
-    /**
-     * Check to see if ability should be triggered.
-     *
-     * @param player The player using the ability
-     * @param block The block modified by the ability
-     * @param ability The ability to check
-     * @return true if the ability should activate, false otherwise
-     */
-    public static boolean triggerCheck(Player player, Block block, AbilityType ability) {
-        boolean activate = true;
-
-        switch (ability) {
-            case BERSERK:
-            case BLOCK_CRACKER:
-            case LEAF_BLOWER:
-                if (!ability.blockCheck(block.getState())) {
-                    activate = false;
-                    break;
-                }
-
-                if (!blockBreakSimulate(block, player, true)) {
-                    activate = false;
-                    break;
-                }
-                break;
-
-            case GIGA_DRILL_BREAKER:
-            case SUPER_BREAKER:
-            case GREEN_TERRA:
-                if (!ability.blockCheck(block.getState())) {
-                    activate = false;
-                    break;
-                }
-                break;
-
-            default:
-                activate = false;
-                break;
-        }
-
-        return activate;
+        return Config.getInstance().getLocale().equalsIgnoreCase("en_US") ? SkillType.getSkill(skillName) != null : isLocalizedSkill(skillName);
     }
 
     public static void sendSkillMessage(Player player, String message) {
+        Location location = player.getLocation();
+
         for (Player otherPlayer : player.getWorld().getPlayers()) {
-            if (otherPlayer != player && Misc.isNear(player.getLocation(), otherPlayer.getLocation(), Misc.SKILL_MESSAGE_MAX_SENDING_DISTANCE)) {
+            if (otherPlayer != player && Misc.isNear(location, otherPlayer.getLocation(), Misc.SKILL_MESSAGE_MAX_SENDING_DISTANCE)) {
                 otherPlayer.sendMessage(message);
             }
         }
@@ -408,48 +132,39 @@ public class SkillUtils {
     }
 
     public static void handleAbilitySpeedDecrease(Player player) {
-        if (HiddenConfig.getInstance().useEnchantmentBuffs()) {
-            PlayerInventory playerInventory = player.getInventory();
-
-            for (int i = 0; i < playerInventory.getContents().length; i++) {
-                ItemStack item = playerInventory.getItem(i);
-                playerInventory.setItem(i, removeAbilityBuff(item));
-            }
+        if (!HiddenConfig.getInstance().useEnchantmentBuffs()) {
+            return;
         }
-    }
 
-    public static ItemStack removeAbilityBuff(ItemStack item) {
-        if (item == null || item.getType() == Material.AIR) {
-            return item;
+        for (ItemStack item : player.getInventory().getContents()) {
+            removeAbilityBuff(item);
         }
+    }
 
-        if (!ItemUtils.isPickaxe(item) && !ItemUtils.isShovel(item)) {
-            return item;
+    public static void removeAbilityBuff(ItemStack item) {
+        if (item == null || item.getType() == Material.AIR || (!ItemUtils.isPickaxe(item) && !ItemUtils.isShovel(item)) || !item.containsEnchantment(Enchantment.DIG_SPEED)) {
+            return;
         }
 
-        if (item.containsEnchantment(Enchantment.DIG_SPEED)) {
-            ItemMeta itemMeta = item.getItemMeta();
+        ItemMeta itemMeta = item.getItemMeta();
 
-            if (itemMeta.hasLore()) {
-                List<String> itemLore = itemMeta.getLore();
+        if (itemMeta.hasLore()) {
+            List<String> itemLore = itemMeta.getLore();
 
-                if (itemLore.remove("mcMMO Ability Tool")) {
-                    int efficiencyLevel = item.getEnchantmentLevel(Enchantment.DIG_SPEED);
+            if (itemLore.remove("mcMMO Ability Tool")) {
+                int efficiencyLevel = item.getEnchantmentLevel(Enchantment.DIG_SPEED);
 
-                    if (efficiencyLevel <= AdvancedConfig.getInstance().getEnchantBuff()) {
-                        itemMeta.removeEnchant(Enchantment.DIG_SPEED);
-                    }
-                    else {
-                        itemMeta.addEnchant(Enchantment.DIG_SPEED, efficiencyLevel - AdvancedConfig.getInstance().getEnchantBuff(), true);
-                    }
-
-                    itemMeta.setLore(itemLore);
-                    item.setItemMeta(itemMeta);
+                if (efficiencyLevel <= AdvancedConfig.getInstance().getEnchantBuff()) {
+                    itemMeta.removeEnchant(Enchantment.DIG_SPEED);
+                }
+                else {
+                    itemMeta.addEnchant(Enchantment.DIG_SPEED, efficiencyLevel - AdvancedConfig.getInstance().getEnchantBuff(), true);
                 }
+
+                itemMeta.setLore(itemLore);
+                item.setItemMeta(itemMeta);
             }
         }
-
-        return item;
     }
 
     /**
@@ -458,53 +173,29 @@ public class SkillUtils {
      * @param itemStack The ItemStack which durability should be modified
      * @return the itemStack with modified durability
      */
-    public static ItemStack handleDurabilityChange(ItemStack itemStack, int durabilityModifier) {
-        short finalDurability = (short) (itemStack.getDurability() + durabilityModifier);
-        short maxDurability = itemStack.getType().getMaxDurability();
-        boolean overMax = (finalDurability >= maxDurability);
-
-        itemStack.setDurability(overMax ? maxDurability : finalDurability);
-        return itemStack;
-    }
-
-    /**
-     * Simulate a block break event.
-     *
-     * @param block The block to break
-     * @param player The player breaking the block
-     * @param shouldArmSwing true if an armswing event should be fired, false otherwise
-     * @return true if the event wasn't cancelled, false otherwise
-     */
-    public static boolean blockBreakSimulate(Block block, Player player, boolean shouldArmSwing) {
-        PluginManager pluginManger = mcMMO.p.getServer().getPluginManager();
-
-        // Support for NoCheat
-        if (shouldArmSwing) {
-            pluginManger.callEvent(new FakePlayerAnimationEvent(player));
-        }
-
-        FakeBlockDamageEvent damageEvent = new FakeBlockDamageEvent(player, block, player.getItemInHand(), true);
-        pluginManger.callEvent(damageEvent);
-
-        FakeBlockBreakEvent breakEvent = new FakeBlockBreakEvent(block, player);
-        pluginManger.callEvent(breakEvent);
-
-        return !damageEvent.isCancelled() && !breakEvent.isCancelled();
+    public static void handleDurabilityChange(ItemStack itemStack, int durabilityModifier) {
+        itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, itemStack.getType().getMaxDurability()));
     }
 
     public static boolean activationSuccessful(Player player, SkillType skill, double maxChance, int maxLevel) {
-        int skillLevel = UserManager.getPlayer(player).getProfile().getSkillLevel(skill);
-        int activationChance = PerksUtils.handleLuckyPerks(player, skill);
-        double chance = (maxChance / maxLevel) * Math.min(skillLevel, maxLevel);
-
-        return chance > Misc.getRandom().nextInt(activationChance);
+        return activationSuccessful(UserManager.getPlayer(player).getProfile().getSkillLevel(skill), PerksUtils.handleLuckyPerks(player, skill), maxChance, maxLevel);
     }
 
     public static boolean activationSuccessful(int skillLevel, int activationChance, double maxChance, int maxLevel) {
-        return ((maxChance / maxLevel) * Math.min(skillLevel, maxLevel)) > Misc.getRandom().nextInt(activationChance);
+        return (maxChance / maxLevel) * Math.min(skillLevel, maxLevel) > Misc.getRandom().nextInt(activationChance);
     }
 
     public static boolean treasureDropSuccessful(double dropChance, int activationChance) {
         return dropChance > Misc.getRandom().nextDouble() * activationChance;
     }
+
+    private static boolean isLocalizedSkill(String skillName) {
+        for (SkillType skill : SkillType.values()) {
+            if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".SkillName"))) {
+                return true;
+            }
+        }
+
+        return false;
+    }
 }

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

@@ -757,6 +757,7 @@ Skills.Header=[[RED]]-----[][[GREEN]]{0}[[RED]][]-----
 Skills.NeedMore=[[DARK_RED]]You need more [[GRAY]]{0}
 Skills.Parents = PARENTS
 Skills.Stats=[[YELLOW]]{0}[[GREEN]]{1}[[DARK_AQUA]] XP([[GRAY]]{2}[[DARK_AQUA]]/[[GRAY]]{3}[[DARK_AQUA]])
+Skills.ChildStats=[[YELLOW]]{0}[[GREEN]]{1}
 Skills.TooTired=[[RED]]You are too tired to use that ability again. [[YELLOW]]({0}s)
 Skills.Cancelled=[[RED]]{0} cancelled!
 Skills.ConfirmOrCancel=[[GREEN]]Right-click again to confirm [[GOLD]]{0}[[GREEN]]. Left-click to cancel.