GJ 11 роки тому
батько
коміт
69ef7f40d8
46 змінених файлів з 835 додано та 884 видалено
  1. 8 8
      src/main/java/com/gmail/nossr50/api/ChatAPI.java
  2. 1 2
      src/main/java/com/gmail/nossr50/commands/KrakenCommand.java
  3. 8 9
      src/main/java/com/gmail/nossr50/commands/McconvertCommand.java
  4. 2 6
      src/main/java/com/gmail/nossr50/commands/XprateCommand.java
  5. 13 16
      src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java
  6. 12 10
      src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java
  7. 6 3
      src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java
  8. 8 4
      src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java
  9. 21 62
      src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java
  10. 11 4
      src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java
  11. 49 42
      src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java
  12. 18 16
      src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java
  13. 22 36
      src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java
  14. 18 16
      src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java
  15. 10 12
      src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java
  16. 6 9
      src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java
  17. 6 8
      src/main/java/com/gmail/nossr50/commands/party/PartyExpShareCommand.java
  18. 21 29
      src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java
  19. 10 12
      src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java
  20. 19 38
      src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java
  21. 16 39
      src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java
  22. 6 6
      src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java
  23. 24 23
      src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java
  24. 23 22
      src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java
  25. 27 26
      src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java
  26. 19 18
      src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java
  27. 52 48
      src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java
  28. 35 35
      src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java
  29. 32 30
      src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java
  30. 33 30
      src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
  31. 36 41
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  32. 9 11
      src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java
  33. 28 26
      src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java
  34. 27 26
      src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java
  35. 40 40
      src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java
  36. 29 28
      src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java
  37. 24 23
      src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java
  38. 38 0
      src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java
  39. 0 46
      src/main/java/com/gmail/nossr50/datatypes/chat/ChatMode.java
  40. 54 14
      src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
  41. 4 1
      src/main/java/com/gmail/nossr50/datatypes/skills/SkillType.java
  42. 3 3
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  43. 2 1
      src/main/java/com/gmail/nossr50/party/PartyManager.java
  44. 1 1
      src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java
  45. 2 2
      src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java
  46. 2 2
      src/main/resources/locale/locale_en_US.properties

+ 8 - 8
src/main/java/com/gmail/nossr50/api/ChatAPI.java

@@ -76,7 +76,7 @@ public final class ChatAPI {
      * @return true if the player is using party chat, false otherwise
      */
     public static boolean isUsingPartyChat(Player player) {
-        return UserManager.getPlayer(player).getPartyChatMode();
+        return UserManager.getPlayer(player).isChatEnabled(ChatMode.PARTY);
     }
 
     /**
@@ -86,7 +86,7 @@ public final class ChatAPI {
      * @return true if the player is using party chat, false otherwise
      */
     public static boolean isUsingPartyChat(String playerName) {
-        return UserManager.getPlayer(playerName).getPartyChatMode();
+        return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.PARTY);
     }
 
     /**
@@ -96,7 +96,7 @@ public final class ChatAPI {
      * @return true if the player is using admin chat, false otherwise
      */
     public static boolean isUsingAdminChat(Player player) {
-        return UserManager.getPlayer(player).getAdminChatMode();
+        return UserManager.getPlayer(player).isChatEnabled(ChatMode.ADMIN);
     }
 
     /**
@@ -106,7 +106,7 @@ public final class ChatAPI {
      * @return true if the player is using admin chat, false otherwise
      */
     public static boolean isUsingAdminChat(String playerName) {
-        return UserManager.getPlayer(playerName).getAdminChatMode();
+        return UserManager.getPlayer(playerName).isChatEnabled(ChatMode.ADMIN);
     }
 
     /**
@@ -115,7 +115,7 @@ public final class ChatAPI {
      * @param player The player to toggle party chat on.
      */
     public static void togglePartyChat(Player player) {
-        UserManager.getPlayer(player).togglePartyChat();
+        UserManager.getPlayer(player).toggleChat(ChatMode.PARTY);
     }
 
     /**
@@ -124,7 +124,7 @@ public final class ChatAPI {
      * @param playerName The name of the player to toggle party chat on.
      */
     public static void togglePartyChat(String playerName) {
-        UserManager.getPlayer(playerName).togglePartyChat();
+        UserManager.getPlayer(playerName).toggleChat(ChatMode.PARTY);
     }
 
     /**
@@ -133,7 +133,7 @@ public final class ChatAPI {
      * @param player The player to toggle admin chat on.
      */
     public static void toggleAdminChat(Player player) {
-        UserManager.getPlayer(player).toggleAdminChat();
+        UserManager.getPlayer(player).toggleChat(ChatMode.ADMIN);
     }
 
     /**
@@ -142,7 +142,7 @@ public final class ChatAPI {
      * @param playerName The name of the player to toggle party chat on.
      */
     public static void toggleAdminChat(String playerName) {
-        UserManager.getPlayer(playerName).toggleAdminChat();
+        UserManager.getPlayer(playerName).toggleChat(ChatMode.ADMIN);
     }
 
     private static ChatManager getPartyChatManager(Plugin plugin, String party) {

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

@@ -7,7 +7,6 @@ import java.util.Set;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
 import org.bukkit.command.TabExecutor;
-import org.bukkit.entity.Player;
 import org.bukkit.util.StringUtil;
 
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
@@ -32,7 +31,7 @@ public class KrakenCommand implements TabExecutor {
                     return true;
                 }
 
-                UserManager.getPlayer((Player) sender).getFishingManager().unleashTheKraken();
+                UserManager.getPlayer(sender.getName()).getFishingManager().unleashTheKraken();
                 return true;
 
             case 1:

+ 8 - 9
src/main/java/com/gmail/nossr50/commands/database/McconvertCommand.java → src/main/java/com/gmail/nossr50/commands/McconvertCommand.java

@@ -1,4 +1,4 @@
-package com.gmail.nossr50.commands.database;
+package com.gmail.nossr50.commands;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -11,6 +11,7 @@ import org.bukkit.command.TabExecutor;
 import org.bukkit.util.StringUtil;
 
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.commands.database.ConvertDatabaseCommand;
 import com.gmail.nossr50.commands.experience.ConvertExperienceCommand;
 import com.gmail.nossr50.database.DatabaseManagerFactory;
 import com.gmail.nossr50.datatypes.database.DatabaseType;
@@ -23,23 +24,17 @@ public class McconvertCommand implements TabExecutor {
     private static final List<String> DATABASE_TYPES;
     private static final List<String> SUBCOMMANDS = ImmutableList.of("database", "experience");
 
-    private CommandExecutor databaseConvertCommand   = new ConvertDatabaseCommand();
+    private CommandExecutor databaseConvertCommand = new ConvertDatabaseCommand();
     private CommandExecutor experienceConvertCommand = new ConvertExperienceCommand();
 
     static {
         ArrayList<String> formulaTypes = new ArrayList<String>();
+        ArrayList<String> databaseTypes = new ArrayList<String>();
 
         for (FormulaType type : FormulaType.values()) {
             formulaTypes.add(type.toString());
         }
 
-        Collections.sort(formulaTypes);
-        FORMULA_TYPES = ImmutableList.copyOf(formulaTypes);
-    }
-
-    static {
-        ArrayList<String> databaseTypes = new ArrayList<String>();
-
         for (DatabaseType type : DatabaseType.values()) {
             databaseTypes.add(type.toString());
         }
@@ -51,8 +46,12 @@ public class McconvertCommand implements TabExecutor {
             databaseTypes.add(DatabaseManagerFactory.getCustomDatabaseManagerClass().getName());
         }
 
+        Collections.sort(formulaTypes);
         Collections.sort(databaseTypes);
+
+        FORMULA_TYPES = ImmutableList.copyOf(formulaTypes);
         DATABASE_TYPES = ImmutableList.copyOf(databaseTypes);
+
     }
 
     @Override

+ 2 - 6
src/main/java/com/gmail/nossr50/commands/XprateCommand.java

@@ -18,11 +18,7 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.google.common.collect.ImmutableList;
 
 public class XprateCommand implements TabExecutor {
-    private double originalRate;
-
-    public XprateCommand() {
-        originalRate = ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier();
-    }
+    private final double ORIGINAL_XP_RATE = ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier();
 
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
@@ -42,7 +38,7 @@ public class XprateCommand implements TabExecutor {
                     mcMMO.p.toggleXpEventEnabled();
                 }
 
-                ExperienceConfig.getInstance().setExperienceGainsGlobalMultiplier(originalRate);
+                ExperienceConfig.getInstance().setExperienceGainsGlobalMultiplier(ORIGINAL_XP_RATE);
                 return true;
 
             case 2:

+ 13 - 16
src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java

@@ -21,9 +21,8 @@ import com.gmail.nossr50.util.player.UserManager;
 import com.google.common.collect.ImmutableList;
 
 public abstract class ChatCommand implements TabExecutor {
-    protected ChatMode chatMode;
+    private ChatMode chatMode;
     protected ChatManager chatManager;
-    private McMMOPlayer mcMMOPlayer;
 
     public ChatCommand(ChatMode chatMode) {
         this.chatMode = chatMode;
@@ -32,19 +31,21 @@ public abstract class ChatCommand implements TabExecutor {
 
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+        McMMOPlayer mcMMOPlayer;
+
         switch (args.length) {
             case 0:
                 if (CommandUtils.noConsoleUsage(sender)) {
                     return true;
                 }
 
-                mcMMOPlayer = UserManager.getPlayer((Player) sender);
+                mcMMOPlayer = UserManager.getPlayer(sender.getName());
 
-                if (chatMode.isEnabled(mcMMOPlayer)) {
-                    disableChatMode(sender);
+                if (mcMMOPlayer.isChatEnabled(chatMode)) {
+                    disableChatMode(mcMMOPlayer, sender);
                 }
                 else {
-                    enableChatMode(sender);
+                    enableChatMode(mcMMOPlayer, sender);
                 }
 
                 return true;
@@ -55,9 +56,7 @@ public abstract class ChatCommand implements TabExecutor {
                         return true;
                     }
 
-                    mcMMOPlayer = UserManager.getPlayer((Player) sender);
-
-                    enableChatMode(sender);
+                    enableChatMode(UserManager.getPlayer(sender.getName()), sender);
                     return true;
                 }
 
@@ -66,9 +65,7 @@ public abstract class ChatCommand implements TabExecutor {
                         return true;
                     }
 
-                    mcMMOPlayer = UserManager.getPlayer((Player) sender);
-
-                    disableChatMode(sender);
+                    disableChatMode(UserManager.getPlayer(sender.getName()), sender);
                     return true;
                 }
 
@@ -108,23 +105,23 @@ public abstract class ChatCommand implements TabExecutor {
 
     protected abstract void handleChatSending(CommandSender sender, String[] args);
 
-    private void enableChatMode(CommandSender sender) {
+    private void enableChatMode(McMMOPlayer mcMMOPlayer, CommandSender sender) {
         if (chatMode == ChatMode.PARTY && mcMMOPlayer.getParty() == null) {
             sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
             return;
         }
 
-        chatMode.enable(mcMMOPlayer);
+        mcMMOPlayer.enableChat(chatMode);
         sender.sendMessage(chatMode.getEnabledMessage());
     }
 
-    private void disableChatMode(CommandSender sender) {
+    private void disableChatMode(McMMOPlayer mcMMOPlayer, CommandSender sender) {
         if (chatMode == ChatMode.PARTY && mcMMOPlayer.getParty() == null) {
             sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
             return;
         }
 
-        chatMode.disable(mcMMOPlayer);
+        mcMMOPlayer.disableChat(chatMode);
         sender.sendMessage(chatMode.getDisabledMessage());
     }
 }

+ 12 - 10
src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java

@@ -15,19 +15,21 @@ import com.google.common.collect.ImmutableList;
 public class MmoshowdbCommand implements TabExecutor {
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
-        if (args.length != 0) {
-            return false;
-        }
+        switch (args.length) {
+            case 0:
+                Class<?> clazz = DatabaseManagerFactory.getCustomDatabaseManagerClass();
 
-        Class<?> clazz = DatabaseManagerFactory.getCustomDatabaseManagerClass();
+                if (clazz != null) {
+                    sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", clazz.getName()));
+                    return true;
+                }
 
-        if (clazz != null) {
-            sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", clazz.getName()));
-            return true;
-        }
+                sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (Config.getInstance().getUseMySQL() ? "sql" : "flatfile")));
+                return true;
 
-        sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (Config.getInstance().getUseMySQL() ? "sql" : "flatfile")));
-        return true;
+            default:
+                return false;
+        }
     }
 
     @Override

+ 6 - 3
src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java

@@ -1,7 +1,9 @@
 package com.gmail.nossr50.commands.experience;
 
 import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
 
+import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.EventUtils;
@@ -19,11 +21,12 @@ public class AddlevelsCommand extends ExperienceCommand {
     }
 
     @Override
-    protected void handleCommand(SkillType skill) {
+    protected void handleCommand(Player player, PlayerProfile profile, SkillType skill, int value) {
         float xpRemoved = profile.getSkillXpLevelRaw(skill);
         profile.addLevels(skill, value);
 
         if (player == null) {
+            profile.save();
             return;
         }
 
@@ -31,12 +34,12 @@ public class AddlevelsCommand extends ExperienceCommand {
     }
 
     @Override
-    protected void handlePlayerMessageAll() {
+    protected void handlePlayerMessageAll(Player player, int value) {
         player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.1", value));
     }
 
     @Override
-    protected void handlePlayerMessageSkill() {
+    protected void handlePlayerMessageSkill(Player player, int value, SkillType skill) {
         player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getName()));
     }
 }

+ 8 - 4
src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java

@@ -1,10 +1,13 @@
 package com.gmail.nossr50.commands.experience;
 
 import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
 
+import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
 
 public class AddxpCommand extends ExperienceCommand {
     @Override
@@ -18,22 +21,23 @@ public class AddxpCommand extends ExperienceCommand {
     }
 
     @Override
-    protected void handleCommand(SkillType skill) {
+    protected void handleCommand(Player player, PlayerProfile profile, SkillType skill, int value) {
         if (player != null) {
-            mcMMOPlayer.applyXpGain(skill, value);
+            UserManager.getPlayer(player).applyXpGain(skill, value);
         }
         else {
             profile.addXp(skill, value);
+            profile.save();
         }
     }
 
     @Override
-    protected void handlePlayerMessageAll() {
+    protected void handlePlayerMessageAll(Player player, int value) {
         player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardAll", value));
     }
 
     @Override
-    protected void handlePlayerMessageSkill() {
+    protected void handlePlayerMessageSkill(Player player, int value, SkillType skill) {
         player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getName()));
     }
 }

+ 21 - 62
src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java

@@ -22,14 +22,6 @@ import com.gmail.nossr50.util.player.UserManager;
 import com.google.common.collect.ImmutableList;
 
 public abstract class ExperienceCommand implements TabExecutor {
-    protected McMMOPlayer mcMMOPlayer;
-    protected Player player;
-    protected PlayerProfile profile;
-
-    protected boolean allSkills;
-    protected SkillType skill;
-    protected int value;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         switch (args.length) {
@@ -47,12 +39,7 @@ public abstract class ExperienceCommand implements TabExecutor {
                     return true;
                 }
 
-                player = (Player) sender;
-                mcMMOPlayer = UserManager.getPlayer(player);
-                profile = mcMMOPlayer.getProfile();
-
-                editValues();
-                cleanUp();
+                editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), SkillType.getSkill(args[0]), Integer.parseInt(args[1]));
                 return true;
 
             case 3:
@@ -65,28 +52,27 @@ public abstract class ExperienceCommand implements TabExecutor {
                     return true;
                 }
 
+                SkillType skill = SkillType.getSkill(args[1]);
+                int value = Integer.parseInt(args[2]);
+
                 String playerName = Misc.getMatchedPlayerName(args[0]);
-                mcMMOPlayer = UserManager.getPlayer(playerName, true);
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(playerName, true);
 
                 // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
                 if (mcMMOPlayer == null) {
-                    profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false);
+                    PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false);
 
                     if (CommandUtils.unloadedProfile(sender, profile)) {
                         return true;
                     }
 
-                    editValues();
-                    profile.save(); // Since this is a temporary profile, we save it here.
+                    editValues(null, profile, skill, value);
                 }
                 else {
-                    profile = mcMMOPlayer.getProfile();
-                    player = mcMMOPlayer.getPlayer();
-                    editValues();
+                    editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, value);
                 }
 
-                handleSenderMessage(sender, playerName);
-                cleanUp();
+                handleSenderMessage(sender, playerName, skill);
                 return true;
 
             default:
@@ -109,42 +95,20 @@ public abstract class ExperienceCommand implements TabExecutor {
 
     protected abstract boolean permissionsCheckSelf(CommandSender sender);
     protected abstract boolean permissionsCheckOthers(CommandSender sender);
-    protected abstract void handleCommand(SkillType skill);
-    protected abstract void handlePlayerMessageAll();
-    protected abstract void handlePlayerMessageSkill();
+    protected abstract void handleCommand(Player player, PlayerProfile profile, SkillType skill, int value);
+    protected abstract void handlePlayerMessageAll(Player player, int value);
+    protected abstract void handlePlayerMessageSkill(Player player, int value, SkillType skill);
 
     private boolean validateArguments(CommandSender sender, String skillName, String value) {
-        if (isInvalidInteger(sender, value) || isInvalidSkill(sender, skillName)) {
+        if (CommandUtils.isInvalidInteger(sender, value) || CommandUtils.isInvalidSkill(sender, skillName)) {
             return false;
         }
 
         return true;
     }
 
-    private boolean isInvalidInteger(CommandSender sender, String value) {
-        if (CommandUtils.isInvalidInteger(sender, value)) {
-            return true;
-        }
-
-        this.value = Integer.parseInt(value);
-        return false;
-    }
-
-    protected boolean isInvalidSkill(CommandSender sender, String skillName) {
-        if (skillName.equalsIgnoreCase("all")) {
-            allSkills = true;
-            return false;
-        }
-        else if (CommandUtils.isInvalidSkill(sender, skillName)) {
-            return true;
-        }
-
-        skill = SkillType.getSkill(skillName);
-        return false;
-    }
-
-    protected void handleSenderMessage(CommandSender sender, String playerName) {
-        if (allSkills) {
+    protected static void handleSenderMessage(CommandSender sender, String playerName, SkillType skill) {
+        if (skill == null) {
             sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
         }
         else {
@@ -152,27 +116,22 @@ public abstract class ExperienceCommand implements TabExecutor {
         }
     }
 
-    protected void editValues() {
-        if (allSkills) {
+    protected void editValues(Player player, PlayerProfile profile, SkillType skill, int value) {
+        if (skill == null) {
             for (SkillType skillType : SkillType.values()) {
-                handleCommand(skillType);
+                handleCommand(player, profile, skillType, value);
             }
 
             if (player != null) {
-                handlePlayerMessageAll();
+                handlePlayerMessageAll(player, value);
             }
         }
         else {
-            handleCommand(skill);
+            handleCommand(player, profile, skill, value);
 
             if (player != null) {
-                handlePlayerMessageSkill();
+                handlePlayerMessageSkill(player, value, skill);
             }
         }
     }
-
-    private void cleanUp() {
-        allSkills = false;
-        player = null;
-    }
 }

+ 11 - 4
src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java

@@ -1,7 +1,9 @@
 package com.gmail.nossr50.commands.experience;
 
 import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
 
+import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.EventUtils;
@@ -19,13 +21,18 @@ public class MmoeditCommand extends ExperienceCommand {
     }
 
     @Override
-    protected void handleCommand(SkillType skill) {
+    protected void handleCommand(Player player, PlayerProfile profile, SkillType skill, int value) {
         int skillLevel = profile.getSkillLevel(skill);
         float xpRemoved = profile.getSkillXpLevelRaw(skill);
 
         profile.modifySkill(skill, value);
 
-        if (player == null || value == skillLevel) {
+        if (player == null) {
+            profile.save();
+            return;
+        }
+
+        if (value == skillLevel) {
             return;
         }
 
@@ -33,12 +40,12 @@ public class MmoeditCommand extends ExperienceCommand {
     }
 
     @Override
-    protected void handlePlayerMessageAll() {
+    protected void handlePlayerMessageAll(Player player, int value) {
         player.sendMessage(LocaleLoader.getString("Commands.mmoedit.AllSkills.1", value));
     }
 
     @Override
-    protected void handlePlayerMessageSkill() {
+    protected void handlePlayerMessageSkill(Player player, int value, SkillType skill) {
         player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getName(), value));
     }
 }

+ 49 - 42
src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java

@@ -1,10 +1,18 @@
 package com.gmail.nossr50.commands.experience;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabExecutor;
 import org.bukkit.entity.Player;
+import org.bukkit.util.StringUtil;
 
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.EventUtils;
@@ -12,18 +20,11 @@ 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.google.common.collect.ImmutableList;
 
-public class SkillresetCommand extends ExperienceCommand {
-    private CommandSender sender;
-    private Command command;
-    private int argsLength;
-
+public class SkillresetCommand implements TabExecutor {
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
-        this.command = command;
-        this.sender = sender;
-        argsLength = args.length;
-
         switch (args.length) {
             case 1:
                 if (CommandUtils.noConsoleUsage(sender)) {
@@ -35,15 +36,11 @@ public class SkillresetCommand extends ExperienceCommand {
                     return true;
                 }
 
-                if (isInvalidSkill(sender, args[0])) {
+                if (CommandUtils.isInvalidSkill(sender, args[0])) {
                     return true;
                 }
 
-                player = (Player) sender;
-                mcMMOPlayer = UserManager.getPlayer(player);
-                profile = mcMMOPlayer.getProfile();
-
-                editValues();
+                editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), SkillType.getSkill(args[0]), args.length, sender, command);
                 return true;
 
             case 2:
@@ -52,32 +49,30 @@ public class SkillresetCommand extends ExperienceCommand {
                     return true;
                 }
 
-                if (isInvalidSkill(sender, args[1])) {
+                if (CommandUtils.isInvalidSkill(sender, args[1])) {
                     return true;
                 }
 
+                SkillType skill = SkillType.getSkill(args[1]);
+
                 String playerName = Misc.getMatchedPlayerName(args[0]);
-                mcMMOPlayer = UserManager.getPlayer(playerName, true);
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(playerName, true);
 
                 // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
                 if (mcMMOPlayer == null) {
-                    profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false);
+                    PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false);
 
                     if (CommandUtils.unloadedProfile(sender, profile)) {
                         return true;
                     }
 
-                    editValues();
-                    profile.save(); // Since this is a temporary profile, we save it here.
+                    editValues(null, profile, skill, args.length, sender, command);
                 }
                 else {
-                    profile = mcMMOPlayer.getProfile();
-                    player = mcMMOPlayer.getPlayer();
-
-                    editValues();
+                    editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, args.length, sender, command);
                 }
 
-                handleSenderMessage(sender, playerName);
+                ExperienceCommand.handleSenderMessage(sender, playerName, skill);
                 return true;
 
             default:
@@ -86,17 +81,38 @@ public class SkillresetCommand extends ExperienceCommand {
     }
 
     @Override
-    protected boolean permissionsCheckSelf(CommandSender sender) {
-        return false;
+    public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+        switch (args.length) {
+            case 1:
+                Set<String> playerNames = UserManager.getPlayerNames();
+                return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<String>(playerNames.size()));
+            case 2:
+                return StringUtil.copyPartialMatches(args[1], SkillType.SKILL_NAMES, new ArrayList<String>(SkillType.SKILL_NAMES.size()));
+            default:
+                return ImmutableList.of();
+        }
     }
 
-    @Override
-    protected boolean permissionsCheckOthers(CommandSender sender) {
-        return false;
+    private void editValues(Player player, PlayerProfile profile, SkillType skill, int argsLength, CommandSender sender, Command command) {
+        if (skill == null) {
+            for (SkillType skillType : SkillType.values()) {
+                handleCommand(player, profile, skillType, argsLength, sender, command);
+            }
+
+            if (player != null) {
+                player.sendMessage(LocaleLoader.getString("Commands.Reset.All"));
+            }
+        }
+        else {
+            handleCommand(player, profile, skill, argsLength, sender, command);
+
+            if (player != null) {
+                player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName()));
+            }
+        }
     }
 
-    @Override
-    protected void handleCommand(SkillType skill) {
+    private void handleCommand(Player player, PlayerProfile profile, SkillType skill, int argsLength, CommandSender sender, Command command) {
         if (argsLength == 1 && !Permissions.skillreset(sender, skill) || (argsLength == 2 && !Permissions.skillresetOthers(sender, skill))) {
             sender.sendMessage(command.getPermissionMessage());
             return;
@@ -108,19 +124,10 @@ public class SkillresetCommand extends ExperienceCommand {
         profile.modifySkill(skill, 0);
 
         if (player == null) {
+            profile.save();
             return;
         }
 
         EventUtils.handleLevelChangeEvent(player, skill, levelsRemoved, xpRemoved, false);
     }
-
-    @Override
-    protected void handlePlayerMessageAll() {
-        player.sendMessage(LocaleLoader.getString("Commands.Reset.All"));
-    }
-
-    @Override
-    protected void handlePlayerMessageSkill() {
-        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName()));
-    }
 }

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

@@ -1,5 +1,7 @@
 package com.gmail.nossr50.commands.hardcore;
 
+import org.bukkit.command.CommandSender;
+
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.skills.SkillType;
@@ -8,18 +10,18 @@ import com.gmail.nossr50.util.Permissions;
 
 public class HardcoreCommand extends HardcoreModeCommand {
     @Override
-    protected boolean checkTogglePermissions() {
+    protected boolean checkTogglePermissions(CommandSender sender) {
         return Permissions.hardcoreToggle(sender);
     }
 
     @Override
-    protected boolean checkModifyPermissions() {
+    protected boolean checkModifyPermissions(CommandSender sender) {
         return Permissions.hardcoreModify(sender);
     }
 
     @Override
-    protected boolean checkEnabled(String skill) {
-        if (skill.equalsIgnoreCase("ALL")) {
+    protected boolean checkEnabled(SkillType skill) {
+        if (skill == null) {
             for (SkillType skillType : SkillType.values()) {
                 if (!skillType.getHardcoreStatLossEnabled()) {
                     return false;
@@ -29,35 +31,35 @@ public class HardcoreCommand extends HardcoreModeCommand {
             return true;
         }
 
-        return SkillType.getSkill(skill).getHardcoreStatLossEnabled();
+        return skill.getHardcoreStatLossEnabled();
     }
 
     @Override
-    protected void enable(String skill) {
-        toggle(true);
+    protected void enable(SkillType skill) {
+        toggle(true, skill);
     }
 
     @Override
-    protected void disable(String skill) {
-        toggle(false);
+    protected void disable(SkillType skill) {
+        toggle(false, skill);
     }
 
     @Override
-    protected void modify() {
-        Config.getInstance().setHardcoreDeathStatPenaltyPercentage(newPercent);
-        sender.sendMessage(LocaleLoader.getString("Hardcore.DeathStatLoss.PercentageChanged", percent.format(newPercent / 100D)));
+    protected void modify(CommandSender sender, double newPercentage) {
+        Config.getInstance().setHardcoreDeathStatPenaltyPercentage(newPercentage);
+        sender.sendMessage(LocaleLoader.getString("Hardcore.DeathStatLoss.PercentageChanged", percent.format(newPercentage / 100.0D)));
     }
 
-    private void toggle(boolean enable) {
-        if (skill.equalsIgnoreCase("ALL")) {
+    private void toggle(boolean enable, SkillType skill) {
+        if (skill == null) {
             for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
                 skillType.setHardcoreStatLossEnabled(enable);
             }
         }
         else {
-            SkillType.getSkill(skill).setHardcoreStatLossEnabled(enable);
+            skill.setHardcoreStatLossEnabled(enable);
         }
 
-        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), skill));
+        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : skill.getName())));
     }
 }

+ 22 - 36
src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java

@@ -17,31 +17,22 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.google.common.collect.ImmutableList;
 
 public abstract class HardcoreModeCommand implements TabExecutor {
-    protected CommandSender sender;
-    protected double newPercent;
-    protected DecimalFormat percent;
-    protected String skill;
-
-    public HardcoreModeCommand() {
-        percent = new DecimalFormat("##0.00%");
-    }
+    protected final DecimalFormat percent = new DecimalFormat("##0.00%");
 
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         switch (args.length) {
             case 0:
-                this.sender = sender;
-
-                if (!checkTogglePermissions()) {
+                if (!checkTogglePermissions(sender)) {
                     sender.sendMessage(command.getPermissionMessage());
                     return true;
                 }
 
-                if (checkEnabled("ALL")) {
-                    disable("ALL");
+                if (checkEnabled(null)) {
+                    disable(null);
                 }
                 else {
-                    enable("ALL");
+                    enable(null);
                 }
 
                 return true;
@@ -53,7 +44,7 @@ public abstract class HardcoreModeCommand implements TabExecutor {
                         return true;
                     }
 
-                    enable("ALL");
+                    enable(null);
                     return true;
                 }
 
@@ -63,11 +54,11 @@ public abstract class HardcoreModeCommand implements TabExecutor {
                         return true;
                     }
 
-                    disable("ALL");
+                    disable(null);
                     return true;
                 }
 
-                if (isInvalidPercentage(sender, args[0])) {
+                if (CommandUtils.isInvalidDouble(sender, args[0])) {
                     return true;
                 }
 
@@ -76,16 +67,20 @@ public abstract class HardcoreModeCommand implements TabExecutor {
                     return true;
                 }
 
-                modify();
+                modify(sender, Double.parseDouble(args[0]));
                 return true;
 
 
             case 2:
-                if (!args[0].equalsIgnoreCase("ALL") && CommandUtils.isChildSkill(sender, SkillType.getSkill(args[0]))) {
+                if (CommandUtils.isInvalidSkill(sender, args[0])) {
                     return true;
                 }
 
-                skill = args[0];
+                SkillType skill = SkillType.getSkill(args[0]);
+
+                if (!CommandUtils.isChildSkill(sender, skill)) {
+                    return true;
+                }
 
                 if (CommandUtils.shouldEnableToggle(args[1])) {
                     if (!Permissions.hardcoreToggle(sender)) {
@@ -103,7 +98,7 @@ public abstract class HardcoreModeCommand implements TabExecutor {
                         return true;
                     }
 
-                    disable(skill);
+                    enable(skill);
                     return true;
                 }
 
@@ -128,19 +123,10 @@ public abstract class HardcoreModeCommand implements TabExecutor {
         }
     }
 
-    protected abstract boolean checkTogglePermissions();
-    protected abstract boolean checkModifyPermissions();
-    protected abstract boolean checkEnabled(String skill);
-    protected abstract void enable(String skill);
-    protected abstract void disable(String skill);
-    protected abstract void modify();
-
-    private boolean isInvalidPercentage(CommandSender sender, String value) {
-        if (CommandUtils.isInvalidDouble(sender, value)) {
-            return true;
-        }
-
-        newPercent = Double.parseDouble(value);
-        return false;
-    }
+    protected abstract boolean checkTogglePermissions(CommandSender sender);
+    protected abstract boolean checkModifyPermissions(CommandSender sender);
+    protected abstract boolean checkEnabled(SkillType skill);
+    protected abstract void enable(SkillType skill);
+    protected abstract void disable(SkillType skill);
+    protected abstract void modify(CommandSender sender, double newPercentage);
 }

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

@@ -1,5 +1,7 @@
 package com.gmail.nossr50.commands.hardcore;
 
+import org.bukkit.command.CommandSender;
+
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.skills.SkillType;
@@ -8,18 +10,18 @@ import com.gmail.nossr50.util.Permissions;
 
 public class VampirismCommand extends HardcoreModeCommand {
     @Override
-    protected boolean checkTogglePermissions() {
+    protected boolean checkTogglePermissions(CommandSender sender) {
         return Permissions.vampirismToggle(sender);
     }
 
     @Override
-    protected boolean checkModifyPermissions() {
+    protected boolean checkModifyPermissions(CommandSender sender) {
         return Permissions.vampirismModify(sender);
     }
 
     @Override
-    protected boolean checkEnabled(String skill) {
-        if (skill.equalsIgnoreCase("ALL")) {
+    protected boolean checkEnabled(SkillType skill) {
+        if (skill == null) {
             for (SkillType skillType : SkillType.values()) {
                 if (!skillType.getHardcoreVampirismEnabled()) {
                     return false;
@@ -29,35 +31,35 @@ public class VampirismCommand extends HardcoreModeCommand {
             return true;
         }
 
-        return SkillType.getSkill(skill).getHardcoreVampirismEnabled();
+        return skill.getHardcoreVampirismEnabled();
     }
 
     @Override
-    protected void enable(String skill) {
-        toggle(true);
+    protected void enable(SkillType skill) {
+        toggle(true, skill);
     }
 
     @Override
-    protected void disable(String skill) {
-        toggle(false);
+    protected void disable(SkillType skill) {
+        toggle(false, skill);
     }
 
     @Override
-    protected void modify() {
-        Config.getInstance().setHardcoreVampirismStatLeechPercentage(newPercent);
-        sender.sendMessage(LocaleLoader.getString("Hardcore.Vampirism.PercentageChanged", percent.format(newPercent / 100D)));
+    protected void modify(CommandSender sender, double newPercentage) {
+        Config.getInstance().setHardcoreVampirismStatLeechPercentage(newPercentage);
+        sender.sendMessage(LocaleLoader.getString("Hardcore.Vampirism.PercentageChanged", percent.format(newPercentage / 100.0D)));
     }
 
-    private void toggle(boolean enable) {
-        if (skill.equalsIgnoreCase("ALL")) {
+    private void toggle(boolean enable, SkillType skill) {
+        if (skill == null) {
             for (SkillType skillType : SkillType.NON_CHILD_SKILLS) {
                 skillType.setHardcoreVampirismEnabled(enable);
             }
         }
         else {
-            SkillType.getSkill(skill).setHardcoreVampirismEnabled(enable);
+            skill.setHardcoreVampirismEnabled(enable);
         }
 
-        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.Vampirism.Name"), skill));
+        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.Vampirism.Name"), (skill == null ? "all skills" : skill)));
     }
 }

+ 10 - 12
src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java

@@ -10,24 +10,22 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyChangePasswordCommand implements CommandExecutor {
-    private Party playerParty;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
-        playerParty = UserManager.getPlayer((Player) sender).getParty();
+        Party party = UserManager.getPlayer((Player) sender).getParty();
 
         switch (args.length) {
             case 1:
-                unprotectParty(sender);
+                unprotectParty(party, sender);
                 return true;
 
             case 2:
                 if (args[1].equalsIgnoreCase("clear") || args[1].equalsIgnoreCase("reset")) {
-                    unprotectParty(sender);
+                    unprotectParty(party, sender);
                     return true;
                 }
 
-                protectParty(sender, args[1]);
+                protectParty(party, sender, args[1]);
                 return true;
 
             default:
@@ -37,15 +35,15 @@ public class PartyChangePasswordCommand implements CommandExecutor {
         }
     }
 
-    private void unprotectParty(CommandSender sender) {
-        playerParty.setLocked(true);
-        playerParty.setPassword(null);
+    private void unprotectParty(Party party, CommandSender sender) {
+        party.setLocked(true);
+        party.setPassword(null);
         sender.sendMessage(LocaleLoader.getString("Party.Password.Removed"));
     }
 
-    private void protectParty(CommandSender sender, String password) {
-        playerParty.setLocked(true);
-        playerParty.setPassword(password);
+    private void protectParty(Party party, CommandSender sender, String password) {
+        party.setLocked(true);
+        party.setPassword(password);
         sender.sendMessage(LocaleLoader.getString("Party.Password.Set", password));
     }
 }

+ 6 - 9
src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java

@@ -24,9 +24,6 @@ import com.gmail.nossr50.util.player.UserManager;
 import com.google.common.collect.ImmutableList;
 
 public class PartyCommand implements TabExecutor {
-    private McMMOPlayer mcMMOPlayer;
-    private Player player;
-
     private static final List<String> PARTY_SUBCOMMANDS;
     private static final List<String> EXPSHARE_COMPLETIONS = ImmutableList.of("none", "equal");
     private static final List<String> ITEMSHARE_COMPLETIONS = ImmutableList.of("none", "equal", "random", "loot", "mining", "herbalism", "woodcutting", "misc");
@@ -71,13 +68,13 @@ public class PartyCommand implements TabExecutor {
             return true;
         }
 
-        player = (Player) sender;
-        mcMMOPlayer = UserManager.getPlayer(player);
+        Player player = (Player) sender;
+        McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
 
         if (args.length < 1) {
             if (!mcMMOPlayer.inParty()) {
                 sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-                return printUsage();
+                return printUsage(player);
             }
 
             return partyInfoCommand.onCommand(sender, command, label, args);
@@ -86,7 +83,7 @@ public class PartyCommand implements TabExecutor {
         PartySubcommandType subcommand = PartySubcommandType.getSubcommand(args[0]);
 
         if (subcommand == null) {
-            return printUsage();
+            return printUsage(player);
         }
 
         // Can't use this for lock/unlock since they're handled by the same command
@@ -111,7 +108,7 @@ public class PartyCommand implements TabExecutor {
         // Party member commands
         if (!mcMMOPlayer.inParty()) {
             sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-            return printUsage();
+            return printUsage(player);
         }
 
         switch (subcommand) {
@@ -211,7 +208,7 @@ public class PartyCommand implements TabExecutor {
         }
     }
 
-    private boolean printUsage() {
+    private boolean printUsage(Player player) {
         player.sendMessage(LocaleLoader.getString("Party.Help.0", "/party join"));
         player.sendMessage(LocaleLoader.getString("Party.Help.1", "/party create"));
         player.sendMessage(LocaleLoader.getString("Party.Help.2", "/party ?"));

+ 6 - 8
src/main/java/com/gmail/nossr50/commands/party/PartyExpShareCommand.java

@@ -14,8 +14,6 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyExpShareCommand implements CommandExecutor {
-    private Party playerParty;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         if (!Config.getInstance().getExpShareEnabled()) {
@@ -25,13 +23,13 @@ public class PartyExpShareCommand implements CommandExecutor {
 
         switch (args.length) {
             case 2:
-                playerParty = UserManager.getPlayer((Player) sender).getParty();
+                Party party = UserManager.getPlayer((Player) sender).getParty();
 
                 if (args[1].equalsIgnoreCase("none") || CommandUtils.shouldDisableToggle(args[1])) {
-                    handleChangingShareMode(ShareMode.NONE);
+                    handleChangingShareMode(party, ShareMode.NONE);
                 }
                 else if (args[1].equalsIgnoreCase("equal") || args[1].equalsIgnoreCase("even") || CommandUtils.shouldEnableToggle(args[1])) {
-                    handleChangingShareMode(ShareMode.EQUAL);
+                    handleChangingShareMode(party, ShareMode.EQUAL);
                 }
                 else {
                     sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "expshare", "<NONE | EQUAL>"));
@@ -45,12 +43,12 @@ public class PartyExpShareCommand implements CommandExecutor {
         }
     }
 
-    private void handleChangingShareMode(ShareMode mode) {
-        playerParty.setXpShareMode(mode);
+    private void handleChangingShareMode(Party party, ShareMode mode) {
+        party.setXpShareMode(mode);
 
         String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", LocaleLoader.getString("Party.ShareType.Exp"), LocaleLoader.getString("Party.ShareMode." + StringUtils.getCapitalized(mode.toString())));
 
-        for (Player member : playerParty.getOnlineMembers()) {
+        for (Player member : party.getOnlineMembers()) {
             member.sendMessage(changeModeMessage);
         }
     }

+ 21 - 29
src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java

@@ -16,36 +16,33 @@ import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyInfoCommand implements CommandExecutor {
-    private McMMOPlayer mcMMOPlayer;
-    private Player player;
-    private Party playerParty;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         switch (args.length) {
             case 0:
             case 1:
-                player = (Player) sender;
-                mcMMOPlayer = UserManager.getPlayer(player);
-                playerParty = mcMMOPlayer.getParty();
+                Player player = (Player) sender;
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
+                Party party = mcMMOPlayer.getParty();
 
-                displayPartyHeader();
-                displayShareModeInfo();
-                displayMemberInfo();
+                displayPartyHeader(player, party);
+                displayShareModeInfo(party, player);
+                displayMemberInfo(player, mcMMOPlayer, party);
                 return true;
+
             default:
                 sender.sendMessage(LocaleLoader.getString("Commands.Usage.1", "party", "info"));
                 return true;
         }
     }
 
-    private String createMembersList() {
+    private String createMembersList(Party party) {
         StringBuilder memberList = new StringBuilder();
 
-        for (String memberName : playerParty.getMembers()) {
+        for (String memberName : party.getMembers()) {
             Player member = mcMMO.p.getServer().getPlayerExact(memberName);
 
-            if (playerParty.getLeader().equalsIgnoreCase(memberName)) {
+            if (party.getLeader().equalsIgnoreCase(memberName)) {
                 memberList.append(ChatColor.GOLD);
             }
             else if (member != null) {
@@ -61,10 +58,10 @@ public class PartyInfoCommand implements CommandExecutor {
         return memberList.toString();
     }
 
-    private void displayShareModeInfo() {
+    private void displayShareModeInfo(Party party, Player player) {
         boolean xpShareEnabled = Config.getInstance().getExpShareEnabled();
         boolean itemShareEnabled = Config.getInstance().getItemShareEnabled();
-        boolean itemSharingActive = (playerParty.getItemShareMode() != ShareMode.NONE);
+        boolean itemSharingActive = (party.getItemShareMode() != ShareMode.NONE);
 
         if (!xpShareEnabled && !itemShareEnabled) {
             return;
@@ -75,11 +72,11 @@ public class PartyInfoCommand implements CommandExecutor {
         String separator = "";
 
         if (xpShareEnabled) {
-            expShareInfo = LocaleLoader.getString("Commands.Party.ExpShare", playerParty.getXpShareMode().toString());
+            expShareInfo = LocaleLoader.getString("Commands.Party.ExpShare", party.getXpShareMode().toString());
         }
 
         if (itemShareEnabled) {
-            itemShareInfo = LocaleLoader.getString("Commands.Party.ItemShare", playerParty.getItemShareMode().toString());
+            itemShareInfo = LocaleLoader.getString("Commands.Party.ItemShare", party.getItemShareMode().toString());
         }
 
         if (xpShareEnabled && itemShareEnabled) {
@@ -87,28 +84,23 @@ public class PartyInfoCommand implements CommandExecutor {
         }
 
         player.sendMessage(LocaleLoader.getString("Commands.Party.ShareMode") + expShareInfo + separator + itemShareInfo);
+
         if (itemSharingActive) {
-            player.sendMessage(LocaleLoader.getString("Commands.Party.ItemShareCategories", playerParty.getItemShareCategories()));
+            player.sendMessage(LocaleLoader.getString("Commands.Party.ItemShareCategories", party.getItemShareCategories()));
         }
     }
 
-    private void displayPartyHeader() {
+    private void displayPartyHeader(Player player, Party party) {
         player.sendMessage(LocaleLoader.getString("Commands.Party.Header"));
-
-        if (playerParty.isLocked()) {
-            player.sendMessage(LocaleLoader.getString("Commands.Party.Status", playerParty.getName(), LocaleLoader.getString("Party.Status.Locked")));
-        }
-        else {
-            player.sendMessage(LocaleLoader.getString("Commands.Party.Status", playerParty.getName(), LocaleLoader.getString("Party.Status.Unlocked")));
-        }
+        player.sendMessage(LocaleLoader.getString("Commands.Party.Status", party.getName(), LocaleLoader.getString("Party.Status." + (party.isLocked() ? "Locked" : "Unlocked"))));
     }
 
-    private void displayMemberInfo() {
+    private void displayMemberInfo(Player player, McMMOPlayer mcMMOPlayer, Party party) {
         int membersNear = PartyManager.getNearMembers(mcMMOPlayer).size();
-        int membersOnline = playerParty.getOnlineMembers().size() - 1;
+        int membersOnline = party.getOnlineMembers().size() - 1;
 
         player.sendMessage(LocaleLoader.getString("Commands.Party.Members.Header"));
         player.sendMessage(LocaleLoader.getString("Commands.Party.MembersNear", membersNear, membersOnline));
-        player.sendMessage(createMembersList());
+        player.sendMessage(createMembersList(party));
     }
 }

+ 10 - 12
src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java

@@ -15,8 +15,6 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyItemShareCommand implements CommandExecutor {
-    private Party playerParty;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         if (!Config.getInstance().getItemShareEnabled()) {
@@ -24,9 +22,10 @@ public class PartyItemShareCommand implements CommandExecutor {
             return true;
         }
 
+        Party party = UserManager.getPlayer((Player) sender).getParty();
+
         switch (args.length) {
             case 2:
-                playerParty = UserManager.getPlayer((Player) sender).getParty();
                 ShareMode mode = ShareMode.getShareMode(args[1].toUpperCase());
 
                 if (mode == null) {
@@ -34,11 +33,10 @@ public class PartyItemShareCommand implements CommandExecutor {
                     return true;
                 }
 
-                handleChangingShareMode(mode);
+                handleChangingShareMode(party, mode);
                 return true;
 
             case 3:
-                playerParty = UserManager.getPlayer((Player) sender).getParty();
                 boolean toggle = false;
 
                 if (CommandUtils.shouldEnableToggle(args[2])) {
@@ -53,7 +51,7 @@ public class PartyItemShareCommand implements CommandExecutor {
                 }
 
                 try {
-                    handleToggleItemShareCategory(ItemShareType.valueOf(args[1].toUpperCase()), toggle);
+                    handleToggleItemShareCategory(party, ItemShareType.valueOf(args[1].toUpperCase()), toggle);
                 }
                 catch (IllegalArgumentException ex) {
                     sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "itemshare", "<loot | mining | herbalism | woodcutting | misc> <true | false>"));
@@ -68,22 +66,22 @@ public class PartyItemShareCommand implements CommandExecutor {
         }
     }
 
-    private void handleChangingShareMode(ShareMode mode) {
-        playerParty.setItemShareMode(mode);
+    private void handleChangingShareMode(Party party, ShareMode mode) {
+        party.setItemShareMode(mode);
 
         String changeModeMessage = LocaleLoader.getString("Commands.Party.SetSharing", LocaleLoader.getString("Party.ShareType.Item"), LocaleLoader.getString("Party.ShareMode." + StringUtils.getCapitalized(mode.toString())));
 
-        for (Player member : playerParty.getOnlineMembers()) {
+        for (Player member : party.getOnlineMembers()) {
             member.sendMessage(changeModeMessage);
         }
     }
 
-    private void handleToggleItemShareCategory(ItemShareType type, boolean toggle) {
-        playerParty.setSharingDrops(type, toggle);
+    private void handleToggleItemShareCategory(Party party, ItemShareType type, boolean toggle) {
+        party.setSharingDrops(type, toggle);
 
         String toggleMessage = LocaleLoader.getString("Commands.Party.ToggleShareCategory", StringUtils.getCapitalized(type.toString()), toggle ? "enabled" : "disabled");
 
-        for (Player member : playerParty.getOnlineMembers()) {
+        for (Player member : party.getOnlineMembers()) {
             member.sendMessage(toggleMessage);
         }
     }

+ 19 - 38
src/main/java/com/gmail/nossr50/commands/party/PartyJoinCommand.java

@@ -14,25 +14,33 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyJoinCommand implements CommandExecutor {
-    private McMMOPlayer mcMMOTarget;
-    private Player target;
-    private Party targetParty;
-
-    private McMMOPlayer mcMMOPlayer;
-    private Player player;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
         switch (args.length) {
             case 2:
             case 3:
-                // Verify target exists and is in a different party than the player
-                if (!canJoinParty(sender, args[1])) {
+                String targetName = Misc.getMatchedPlayerName(args[1]);
+                McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName);
+
+                if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) {
                     return true;
                 }
 
-                mcMMOPlayer = UserManager.getPlayer((Player) sender);
-                player = mcMMOPlayer.getPlayer();
+                Player target = mcMMOTarget.getPlayer();
+
+                if (!mcMMOTarget.inParty()) {
+                    sender.sendMessage(LocaleLoader.getString("Party.PlayerNotInParty", targetName));
+                    return true;
+                }
+
+                Player player = (Player) sender;
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
+                Party targetParty = mcMMOTarget.getParty();
+
+                if (player.equals(target) || (mcMMOPlayer.inParty() && mcMMOPlayer.getParty().equals(targetParty))) {
+                    sender.sendMessage(LocaleLoader.getString("Party.Join.Self"));
+                    return true;
+                }
 
                 String password = getPassword(args);
 
@@ -65,31 +73,4 @@ public class PartyJoinCommand implements CommandExecutor {
 
         return null;
     }
-
-    private boolean canJoinParty(CommandSender sender, String targetName) {
-        targetName = Misc.getMatchedPlayerName(targetName);
-        mcMMOTarget = UserManager.getPlayer(targetName);
-
-        if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) {
-            return false;
-        }
-
-        target = mcMMOTarget.getPlayer();
-
-        if (!mcMMOTarget.inParty()) {
-            sender.sendMessage(LocaleLoader.getString("Party.PlayerNotInParty", targetName));
-            return false;
-        }
-
-        player = (Player) sender;
-        mcMMOPlayer = UserManager.getPlayer(player);
-        targetParty = mcMMOTarget.getParty();
-
-        if (player.equals(target) || (mcMMOPlayer.inParty() && mcMMOPlayer.getParty().equals(targetParty))) {
-            sender.sendMessage(LocaleLoader.getString("Party.Join.Self"));
-            return false;
-        }
-
-        return true;
-    }
 }

+ 16 - 39
src/main/java/com/gmail/nossr50/commands/party/PartyLockCommand.java

@@ -12,19 +12,15 @@ import com.gmail.nossr50.util.commands.CommandUtils;
 import com.gmail.nossr50.util.player.UserManager;
 
 public class PartyLockCommand implements CommandExecutor {
-    private Party playerParty;
-
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
-        playerParty = UserManager.getPlayer((Player) sender).getParty();
-
         switch (args.length) {
             case 1:
                 if (args[0].equalsIgnoreCase("lock")) {
-                    lockParty(sender, command.getPermissionMessage());
+                    togglePartyLock(sender, true);
                 }
                 else if (args[0].equalsIgnoreCase("unlock")) {
-                    unlockParty(sender, command.getPermissionMessage());
+                    togglePartyLock(sender, false);
                 }
 
                 return true;
@@ -36,10 +32,10 @@ public class PartyLockCommand implements CommandExecutor {
                 }
 
                 if (CommandUtils.shouldEnableToggle(args[1])) {
-                    lockParty(sender, command.getPermissionMessage());
+                    togglePartyLock(sender, true);
                 }
                 else if (CommandUtils.shouldDisableToggle(args[1])) {
-                    unlockParty(sender, command.getPermissionMessage());
+                    togglePartyLock(sender, false);
                 }
                 else {
                     sendUsageStrings(sender);
@@ -53,44 +49,25 @@ public class PartyLockCommand implements CommandExecutor {
         }
     }
 
-    /**
-     * Handle locking a party.
-     */
-    private void lockParty(CommandSender sender, String permissionMessage) {
-        if (!Permissions.partySubcommand(sender, PartySubcommandType.LOCK)) {
-            sender.sendMessage(permissionMessage);
-            return;
-        }
-
-        if (playerParty.isLocked()) {
-            sender.sendMessage(LocaleLoader.getString("Party.IsLocked"));
-            return;
-        }
-
-        playerParty.setLocked(true);
-        sender.sendMessage(LocaleLoader.getString("Party.Locked"));
+    private void sendUsageStrings(CommandSender sender) {
+        sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "lock", "[on|off]"));
+        sender.sendMessage(LocaleLoader.getString("Commands.Usage.1", "party", "unlock"));
     }
 
-    /**
-     * Handle unlocking a party.
-     */
-    private void unlockParty(CommandSender sender, String permissionMessage) {
-        if (!Permissions.partySubcommand(sender, PartySubcommandType.UNLOCK)) {
-            sender.sendMessage(permissionMessage);
+    private void togglePartyLock(CommandSender sender, boolean lock) {
+        Party party = UserManager.getPlayer((Player) sender).getParty();
+
+        if (!Permissions.partySubcommand(sender, lock ? PartySubcommandType.LOCK : PartySubcommandType.UNLOCK)) {
+            sender.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
             return;
         }
 
-        if (!playerParty.isLocked()) {
-            sender.sendMessage(LocaleLoader.getString("Party.IsntLocked"));
+        if (lock ? party.isLocked() : !party.isLocked()) {
+            sender.sendMessage(LocaleLoader.getString("Party." + (lock ? "IsLocked" : "IsntLocked")));
             return;
         }
 
-        playerParty.setLocked(false);
-        sender.sendMessage(LocaleLoader.getString("Party.Unlocked"));
-    }
-
-    private void sendUsageStrings(CommandSender sender) {
-        sender.sendMessage(LocaleLoader.getString("Commands.Usage.2", "party", "lock", "[on|off]"));
-        sender.sendMessage(LocaleLoader.getString("Commands.Usage.1", "party", "unlock"));
+        party.setLocked(lock);
+        sender.sendMessage(LocaleLoader.getString("Party." + (lock ? "Locked" : "Unlocked")));
     }
 }

+ 6 - 6
src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java

@@ -28,9 +28,6 @@ import com.gmail.nossr50.util.skills.SkillUtils;
 import com.google.common.collect.ImmutableList;
 
 public class PtpCommand implements TabExecutor {
-    private static Player target;
-    private static McMMOPlayer mcMMOTarget;
-
     public static final List<String> TELEPORT_SUBCOMMANDS = ImmutableList.of("toggle", "accept", "acceptany", "acceptall");
 
     private CommandExecutor ptpToggleCommand = new PtpToggleCommand();
@@ -119,6 +116,9 @@ public class PtpCommand implements TabExecutor {
             return;
         }
 
+        McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName);
+        Player target = mcMMOTarget.getPlayer();
+
         PartyTeleportRecord ptpRecord = mcMMOTarget.getPartyTeleportRecord();
 
         if (!ptpRecord.isConfirmRequired()) {
@@ -136,13 +136,13 @@ public class PtpCommand implements TabExecutor {
     }
 
     protected static boolean canTeleport(CommandSender sender, Player player, String targetName) {
-        mcMMOTarget = UserManager.getPlayer(targetName);
+        McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetName);
 
         if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) {
             return false;
         }
 
-        target = mcMMOTarget.getPlayer();
+        Player target = mcMMOTarget.getPlayer();
 
         if (player.equals(target)) {
             player.sendMessage(LocaleLoader.getString("Party.Teleport.Self"));
@@ -169,7 +169,7 @@ public class PtpCommand implements TabExecutor {
 
     protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) {
         McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer);
-        mcMMOTarget = UserManager.getPlayer(targetPlayer);
+        McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetPlayer);
 
         long warmup = Config.getInstance().getPTPCommandWarmup();
 

+ 24 - 23
src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.acrobatics.Acrobatics;
@@ -22,75 +27,71 @@ public class AcrobaticsCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // DODGE
         if (canDodge) {
-            String[] dodgeStrings = calculateAbilityDisplayValues(Acrobatics.dodgeMaxBonusLevel, Acrobatics.dodgeMaxChance);
+            String[] dodgeStrings = calculateAbilityDisplayValues(skillValue, Acrobatics.dodgeMaxBonusLevel, Acrobatics.dodgeMaxChance, isLucky);
             dodgeChance = dodgeStrings[0];
             dodgeChanceLucky = dodgeStrings[1];
         }
 
         // ROLL
         if (canRoll) {
-            String[] rollStrings = calculateAbilityDisplayValues(Acrobatics.rollMaxBonusLevel, Acrobatics.rollMaxChance);
+            String[] rollStrings = calculateAbilityDisplayValues(skillValue, Acrobatics.rollMaxBonusLevel, Acrobatics.rollMaxChance, isLucky);
             rollChance = rollStrings[0];
             rollChanceLucky = rollStrings[1];
         }
 
         // GRACEFUL ROLL
         if (canGracefulRoll) {
-            String[] gracefulRollStrings = calculateAbilityDisplayValues(Acrobatics.gracefulRollMaxBonusLevel, Acrobatics.gracefulRollMaxChance);
+            String[] gracefulRollStrings = calculateAbilityDisplayValues(skillValue, Acrobatics.gracefulRollMaxBonusLevel, Acrobatics.gracefulRollMaxChance, isLucky);
             gracefulRollChance = gracefulRollStrings[0];
             gracefulRollChanceLucky = gracefulRollStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canDodge = Permissions.dodge(player);
         canRoll = Permissions.roll(player);
         canGracefulRoll = Permissions.gracefulRoll(player);
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canDodge || canGracefulRoll || canRoll;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canRoll) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.0"), LocaleLoader.getString("Acrobatics.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.0"), LocaleLoader.getString("Acrobatics.Effect.1")));
         }
 
         if (canGracefulRoll) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.2"), LocaleLoader.getString("Acrobatics.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.2"), LocaleLoader.getString("Acrobatics.Effect.3")));
         }
 
         if (canDodge) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.4"), LocaleLoader.getString("Acrobatics.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Acrobatics.Effect.4"), LocaleLoader.getString("Acrobatics.Effect.5")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canDodge || canGracefulRoll || canRoll;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canRoll) {
-            player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Chance", rollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Acrobatics.Roll.Chance", rollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", rollChanceLucky) : ""));
         }
 
         if (canGracefulRoll) {
-            player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.GraceChance", gracefulRollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", gracefulRollChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Acrobatics.Roll.GraceChance", gracefulRollChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", gracefulRollChanceLucky) : ""));
         }
 
         if (canDodge) {
-            player.sendMessage(LocaleLoader.getString("Acrobatics.DodgeChance", dodgeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dodgeChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Acrobatics.DodgeChance", dodgeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dodgeChanceLucky) : ""));
         }
+
+        return messages;
     }
 }

+ 23 - 22
src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.archery.Archery;
@@ -21,7 +26,7 @@ public class ArcheryCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // SKILL SHOT
         if (canSkillShot) {
             double bonus = (skillValue / Archery.skillShotIncreaseLevel) * Archery.skillShotIncreasePercentage;
@@ -30,65 +35,61 @@ public class ArcheryCommand extends SkillCommand {
 
         // DAZE
         if (canDaze) {
-            String[] dazeStrings = calculateAbilityDisplayValues(Archery.dazeMaxBonusLevel, Archery.dazeMaxBonus);
+            String[] dazeStrings = calculateAbilityDisplayValues(skillValue, Archery.dazeMaxBonusLevel, Archery.dazeMaxBonus, isLucky);
             dazeChance = dazeStrings[0];
             dazeChanceLucky = dazeStrings[1];
         }
 
         // RETRIEVE
         if (canRetrieve) {
-            String[] retrieveStrings = calculateAbilityDisplayValues(Archery.retrieveMaxBonusLevel, Archery.retrieveMaxChance);
+            String[] retrieveStrings = calculateAbilityDisplayValues(skillValue, Archery.retrieveMaxBonusLevel, Archery.retrieveMaxChance, isLucky);
             retrieveChance = retrieveStrings[0];
             retrieveChanceLucky = retrieveStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canSkillShot = Permissions.bonusDamage(player, skill);
         canDaze = Permissions.daze(player);
         canRetrieve = Permissions.arrowRetrieval(player);
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canSkillShot || canDaze || canRetrieve;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canSkillShot) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.0"), LocaleLoader.getString("Archery.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.0"), LocaleLoader.getString("Archery.Effect.1")));
         }
 
         if (canDaze) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.2"), LocaleLoader.getString("Archery.Effect.3", Archery.dazeModifier)));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.2"), LocaleLoader.getString("Archery.Effect.3", Archery.dazeModifier)));
         }
 
         if (canRetrieve) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.4"), LocaleLoader.getString("Archery.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Archery.Effect.4"), LocaleLoader.getString("Archery.Effect.5")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canSkillShot || canDaze || canRetrieve;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canSkillShot) {
-            player.sendMessage(LocaleLoader.getString("Archery.Combat.SkillshotBonus", skillShotBonus));
+            messages.add(LocaleLoader.getString("Archery.Combat.SkillshotBonus", skillShotBonus));
         }
 
         if (canDaze) {
-            player.sendMessage(LocaleLoader.getString("Archery.Combat.DazeChance", dazeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dazeChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Archery.Combat.DazeChance", dazeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", dazeChanceLucky) : ""));
         }
 
         if (canRetrieve) {
-            player.sendMessage(LocaleLoader.getString("Archery.Combat.RetrieveChance", retrieveChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", retrieveChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Archery.Combat.RetrieveChance", retrieveChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", retrieveChanceLucky) : ""));
         }
+
+        return messages;
     }
 }

+ 27 - 26
src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.axes.Axes;
@@ -24,7 +29,7 @@ public class AxesCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // IMPACT
         if (canImpact) {
             impactDamage = 1 + (skillValue / Axes.impactIncreaseLevel);
@@ -32,14 +37,14 @@ public class AxesCommand extends SkillCommand {
 
         // SKULL SPLITTER
         if (canSkullSplitter) {
-            String[] skullSplitterStrings = calculateLengthDisplayValues();
+            String[] skullSplitterStrings = calculateLengthDisplayValues(player, skillValue);
             skullSplitterLength = skullSplitterStrings[0];
             skullSplitterLengthEndurance = skullSplitterStrings[1];
         }
 
         // CRITICAL STRIKES
         if (canCritical) {
-            String[] criticalStrikeStrings = calculateAbilityDisplayValues(Axes.criticalHitMaxBonusLevel, Axes.criticalHitMaxChance);
+            String[] criticalStrikeStrings = calculateAbilityDisplayValues(skillValue, Axes.criticalHitMaxBonusLevel, Axes.criticalHitMaxChance, isLucky);
             critChance = criticalStrikeStrings[0];
             critChanceLucky = criticalStrikeStrings[1];
         }
@@ -51,7 +56,7 @@ public class AxesCommand extends SkillCommand {
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canSkullSplitter = Permissions.skullSplitter(player);
         canCritical = Permissions.criticalStrikes(player);
         canBonusDamage = Permissions.bonusDamage(player, skill);
@@ -60,60 +65,56 @@ public class AxesCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canSkullSplitter || canCritical || canBonusDamage || canImpact || canGreaterImpact;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canSkullSplitter) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.0"), LocaleLoader.getString("Axes.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.0"), LocaleLoader.getString("Axes.Effect.1")));
         }
 
         if (canCritical) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.2"), LocaleLoader.getString("Axes.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.2"), LocaleLoader.getString("Axes.Effect.3")));
         }
 
         if (canBonusDamage) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.4"), LocaleLoader.getString("Axes.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.4"), LocaleLoader.getString("Axes.Effect.5")));
         }
 
         if (canImpact) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.6"), LocaleLoader.getString("Axes.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.6"), LocaleLoader.getString("Axes.Effect.7")));
         }
 
         if (canGreaterImpact) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.8"), LocaleLoader.getString("Axes.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Axes.Effect.8"), LocaleLoader.getString("Axes.Effect.9")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canSkullSplitter || canCritical || canBonusDamage || canImpact || canGreaterImpact;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canBonusDamage) {
-            player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.0"), LocaleLoader.getString("Axes.Ability.Bonus.1", bonusDamage)));
+            messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.0"), LocaleLoader.getString("Axes.Ability.Bonus.1", bonusDamage)));
         }
 
         if (canImpact) {
-            player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.2"), LocaleLoader.getString("Axes.Ability.Bonus.3", impactDamage)));
+            messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.2"), LocaleLoader.getString("Axes.Ability.Bonus.3", impactDamage)));
         }
 
         if (canGreaterImpact) {
-            player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.4"), LocaleLoader.getString("Axes.Ability.Bonus.5", Axes.greaterImpactBonusDamage)));
+            messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Axes.Ability.Bonus.4"), LocaleLoader.getString("Axes.Ability.Bonus.5", Axes.greaterImpactBonusDamage)));
         }
 
         if (canCritical) {
-            player.sendMessage(LocaleLoader.getString("Axes.Combat.CritChance", critChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", critChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Axes.Combat.CritChance", critChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", critChanceLucky) : ""));
         }
 
         if (canSkullSplitter) {
-            player.sendMessage(LocaleLoader.getString("Axes.Combat.SS.Length", skullSplitterLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Axes.Combat.SS.Length", skullSplitterLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : ""));
         }
+
+        return messages;
     }
 }

+ 19 - 18
src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
@@ -16,48 +21,44 @@ public class ExcavationCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // GIGA DRILL BREAKER
         if (canGigaDrill) {
-            String gigaDrillStrings[] = calculateLengthDisplayValues();
+            String gigaDrillStrings[] = calculateLengthDisplayValues(player, skillValue);
             gigaDrillBreakerLength = gigaDrillStrings[0];
             gigaDrillBreakerLengthEndurance = gigaDrillStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canGigaDrill = Permissions.gigaDrillBreaker(player);
         canTreasureHunt = Permissions.excavationTreasureHunter(player);
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canGigaDrill || canTreasureHunt;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canGigaDrill) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Excavation.Effect.0"), LocaleLoader.getString("Excavation.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Excavation.Effect.0"), LocaleLoader.getString("Excavation.Effect.1")));
         }
 
         if (canTreasureHunt) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Excavation.Effect.2"), LocaleLoader.getString("Excavation.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Excavation.Effect.2"), LocaleLoader.getString("Excavation.Effect.3")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canGigaDrill;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canGigaDrill) {
-            player.sendMessage(LocaleLoader.getString("Excavation.Effect.Length", gigaDrillBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", gigaDrillBreakerLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Excavation.Effect.Length", gigaDrillBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", gigaDrillBreakerLengthEndurance) : ""));
         }
+
+        return messages;
     }
 }

+ 52 - 48
src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java

@@ -1,8 +1,12 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.bukkit.Location;
 import org.bukkit.block.Biome;
 import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.treasure.TreasureConfig;
@@ -11,6 +15,7 @@ import com.gmail.nossr50.datatypes.treasure.Rarity;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.fishing.Fishing;
 import com.gmail.nossr50.skills.fishing.Fishing.Tier;
+import com.gmail.nossr50.skills.fishing.FishingManager;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 
@@ -43,48 +48,51 @@ public class FishingCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
+        FishingManager fishingManager = UserManager.getPlayer(player).getFishingManager();
         boolean isStorming = player.getWorld().hasStorm();
 
         // TREASURE HUNTER
         if (canTreasureHunt) {
-            lootTier = mcMMOPlayer.getFishingManager().getLootTier();
+            lootTier = fishingManager.getLootTier();
 
             // Item drop rates
-            trapTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.TRAP))[0];
-            commonTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.COMMON))[0];
-            uncommonTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.UNCOMMON))[0];
-            rareTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RARE))[0];
-            epicTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.EPIC))[0];
-            legendaryTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.LEGENDARY))[0];
-            recordTreasure = calculateAbilityDisplayValues(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RECORD))[0];
+            trapTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.TRAP) / 100.0);
+            commonTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.COMMON) / 100.0);
+            uncommonTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.UNCOMMON) / 100.0);
+            rareTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RARE) / 100.0);
+            epicTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.EPIC) / 100.0);
+            legendaryTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.LEGENDARY) / 100.0);
+            recordTreasure = percent.format(TreasureConfig.getInstance().getItemDropRate(lootTier, Rarity.RECORD) / 100.0);
 
             // Magic hunter drop rates
-            double commonEnchantment = TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, Rarity.COMMON);
-            double uncommonEnchantment = TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, Rarity.UNCOMMON);
-            double rareEnchantment = TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, Rarity.RARE);
-            double epicEnchantment = TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, Rarity.EPIC);
-            double legendaryEnchantment = TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, Rarity.LEGENDARY);
+            double totalEnchantChance = 0;
+
+            for (Rarity rarity : Rarity.values()) {
+                if (rarity != Rarity.TRAP || rarity != Rarity.RECORD) {
+                    totalEnchantChance += TreasureConfig.getInstance().getEnchantmentDropRate(lootTier, rarity);
+                }
+            }
 
-            magicChance = calculateAbilityDisplayValues(commonEnchantment + uncommonEnchantment + rareEnchantment + epicEnchantment + legendaryEnchantment)[0];
+            magicChance = percent.format(totalEnchantChance / 100.0);
         }
 
         // SHAKE
         if (canShake) {
-            String[] shakeStrings = calculateAbilityDisplayValues(UserManager.getPlayer(player).getFishingManager().getShakeProbability());
+            String[] shakeStrings = calculateAbilityDisplayValues(UserManager.getPlayer(player).getFishingManager().getShakeProbability(), isLucky);
             shakeChance = shakeStrings[0];
             shakeChanceLucky = shakeStrings[1];
         }
 
         // FISHERMAN'S DIET
         if (canFishermansDiet) {
-            fishermansDietRank = calculateRank(Fishing.fishermansDietMaxLevel, Fishing.fishermansDietRankLevel1);
+            fishermansDietRank = calculateRank(skillValue, Fishing.fishermansDietMaxLevel, Fishing.fishermansDietRankLevel1);
         }
 
         // MASTER ANGLER
         if (canMasterAngler) {
             double rawBiteChance = 1.0 / (isStorming ? 300 : 500);
-            Location location = mcMMOPlayer.getFishingManager().getHookLocation();
+            Location location = fishingManager.getHookLocation();
 
             if (location == null) {
                 location = player.getLocation();
@@ -100,12 +108,12 @@ public class FishingCommand extends SkillCommand {
                 rawBiteChance = rawBiteChance * AdvancedConfig.getInstance().getMasterAnglerBoatModifier();
             }
 
-            biteChance = calculateAbilityDisplayValues(rawBiteChance * 100.0)[0];
+            biteChance = calculateAbilityDisplayValues(rawBiteChance * 100.0, isLucky)[0];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canTreasureHunt = Permissions.fishingTreasureHunter(player);
         canMagicHunt = Permissions.magicHunter(player);
         canShake = Permissions.shake(player);
@@ -115,63 +123,57 @@ public class FishingCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canTreasureHunt || canMagicHunt || canShake || canMasterAngler || canFishermansDiet || canIceFish;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canTreasureHunt) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.0"), LocaleLoader.getString("Fishing.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.0"), LocaleLoader.getString("Fishing.Effect.1")));
         }
 
         if (canMagicHunt) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.2"), LocaleLoader.getString("Fishing.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.2"), LocaleLoader.getString("Fishing.Effect.3")));
         }
 
         if (canIceFish) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.10"), LocaleLoader.getString("Fishing.Effect.11")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.10"), LocaleLoader.getString("Fishing.Effect.11")));
         }
 
         if (canMasterAngler) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.8"), LocaleLoader.getString("Fishing.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.8"), LocaleLoader.getString("Fishing.Effect.9")));
         }
 
         if (canShake) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.4"), LocaleLoader.getString("Fishing.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.4"), LocaleLoader.getString("Fishing.Effect.5")));
         }
 
         if (canFishermansDiet) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.6"), LocaleLoader.getString("Fishing.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Fishing.Effect.6"), LocaleLoader.getString("Fishing.Effect.7")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canTreasureHunt || canMagicHunt || canShake || canMasterAngler || canFishermansDiet || canIceFish;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canTreasureHunt) {
-            player.sendMessage(LocaleLoader.getString("Fishing.Ability.Rank", lootTier, Tier.EIGHT.toNumerical()));
-            player.sendMessage(LocaleLoader.getString("Fishing.Ability.TH.DropRate", trapTreasure, commonTreasure, uncommonTreasure, rareTreasure, epicTreasure, legendaryTreasure, recordTreasure));
+            messages.add(LocaleLoader.getString("Fishing.Ability.Rank", lootTier, Tier.EIGHT.toNumerical()));
+            messages.add(LocaleLoader.getString("Fishing.Ability.TH.DropRate", trapTreasure, commonTreasure, uncommonTreasure, rareTreasure, epicTreasure, legendaryTreasure, recordTreasure));
         }
 
         if (canMagicHunt) {
-            player.sendMessage(LocaleLoader.getString("Fishing.Ability.TH.MagicRate", magicChance));
+            messages.add(LocaleLoader.getString("Fishing.Ability.TH.MagicRate", magicChance));
         }
 
         if (canIceFish) {
             int unlockLevel = AdvancedConfig.getInstance().getIceFishingUnlockLevel();
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.1", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.1", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Fishing.Ability.IceFishing"));
+                messages.add(LocaleLoader.getString("Fishing.Ability.IceFishing"));
             }
         }
 
@@ -179,10 +181,10 @@ public class FishingCommand extends SkillCommand {
             int unlockLevel = AdvancedConfig.getInstance().getMasterAnglerUnlockLevel();
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.2", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.2", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Fishing.Ability.Chance", biteChance));
+                messages.add(LocaleLoader.getString("Fishing.Ability.Chance", biteChance));
             }
         }
 
@@ -190,15 +192,17 @@ public class FishingCommand extends SkillCommand {
             int unlockLevel = AdvancedConfig.getInstance().getFishingTierLevel(Tier.ONE);
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.0", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Fishing.Ability.Locked.0", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Fishing.Ability.Shake", shakeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shakeChanceLucky) : ""));
+                messages.add(LocaleLoader.getString("Fishing.Ability.Shake", shakeChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shakeChanceLucky) : ""));
             }
         }
 
         if (canFishermansDiet) {
-            player.sendMessage(LocaleLoader.getString("Fishing.Ability.FD", fishermansDietRank));
+            messages.add(LocaleLoader.getString("Fishing.Ability.FD", fishermansDietRank));
         }
+
+        return messages;
     }
 }

+ 35 - 35
src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java

@@ -1,6 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.bukkit.Material;
+import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -34,52 +38,52 @@ public class HerbalismCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // GREEN TERRA
         if (canGreenTerra) {
-            String[] greenTerraStrings = calculateLengthDisplayValues();
+            String[] greenTerraStrings = calculateLengthDisplayValues(player, skillValue);
             greenTerraLength = greenTerraStrings[0];
             greenTerraLengthEndurance = greenTerraStrings[1];
         }
 
         // FARMERS DIET
         if (canFarmersDiet) {
-            farmersDietRank = calculateRank(Herbalism.farmersDietMaxLevel, Herbalism.farmersDietRankLevel1);
+            farmersDietRank = calculateRank(skillValue, Herbalism.farmersDietMaxLevel, Herbalism.farmersDietRankLevel1);
         }
 
         // GREEN THUMB
         if (canGreenThumbBlocks || canGreenThumbPlants) {
-            greenThumbStage = calculateRank(Herbalism.greenThumbStageMaxLevel, Herbalism.greenThumbStageChangeLevel);
+            greenThumbStage = calculateRank(skillValue, Herbalism.greenThumbStageMaxLevel, Herbalism.greenThumbStageChangeLevel);
 
-            String[] greenThumbStrings = calculateAbilityDisplayValues(Herbalism.greenThumbMaxLevel, Herbalism.greenThumbMaxChance);
+            String[] greenThumbStrings = calculateAbilityDisplayValues(skillValue, Herbalism.greenThumbMaxLevel, Herbalism.greenThumbMaxChance, isLucky);
             greenThumbChance = greenThumbStrings[0];
             greenThumbChanceLucky = greenThumbStrings[1];
         }
 
         // DOUBLE DROPS
         if (canDoubleDrop) {
-            String[] doubleDropStrings = calculateAbilityDisplayValues(Herbalism.doubleDropsMaxLevel, Herbalism.doubleDropsMaxChance);
+            String[] doubleDropStrings = calculateAbilityDisplayValues(skillValue, Herbalism.doubleDropsMaxLevel, Herbalism.doubleDropsMaxChance, isLucky);
             doubleDropChance = doubleDropStrings[0];
             doubleDropChanceLucky = doubleDropStrings[1];
         }
 
         // HYLIAN LUCK
         if (hasHylianLuck) {
-            String[] hylianLuckStrings = calculateAbilityDisplayValues(Herbalism.hylianLuckMaxLevel, Herbalism.hylianLuckMaxChance);
+            String[] hylianLuckStrings = calculateAbilityDisplayValues(skillValue, Herbalism.hylianLuckMaxLevel, Herbalism.hylianLuckMaxChance, isLucky);
             hylianLuckChance = hylianLuckStrings[0];
             hylianLuckChanceLucky = hylianLuckStrings[1];
         }
 
         // SHROOM THUMB
         if (canShroomThumb) {
-            String[] shroomThumbStrings = calculateAbilityDisplayValues(Herbalism.shroomThumbMaxLevel, Herbalism.shroomThumbMaxChance);
+            String[] shroomThumbStrings = calculateAbilityDisplayValues(skillValue, Herbalism.shroomThumbMaxLevel, Herbalism.shroomThumbMaxChance, isLucky);
             shroomThumbChance = shroomThumbStrings[0];
             shroomThumbChanceLucky = shroomThumbStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         hasHylianLuck = Permissions.hylianLuck(player);
         canGreenTerra = Permissions.greenTerra(player);
         canGreenThumbPlants = Permissions.greenThumbPlant(player, Material.CROPS) || Permissions.greenThumbPlant(player, Material.CARROT) || Permissions.greenThumbPlant(player, Material.POTATO) || Permissions.greenThumbPlant(player, Material.NETHER_WARTS) || Permissions.greenThumbPlant(player, Material.COCOA);
@@ -90,76 +94,72 @@ public class HerbalismCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canGreenTerra || canDoubleDrop || canFarmersDiet || canGreenThumbBlocks || canGreenThumbPlants || canShroomThumb;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canGreenTerra) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.0"), LocaleLoader.getString("Herbalism.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.0"), LocaleLoader.getString("Herbalism.Effect.1")));
         }
 
         if (canGreenThumbPlants) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.2"), LocaleLoader.getString("Herbalism.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.2"), LocaleLoader.getString("Herbalism.Effect.3")));
         }
 
         if (canGreenThumbBlocks) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.4"), LocaleLoader.getString("Herbalism.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.4"), LocaleLoader.getString("Herbalism.Effect.5")));
         }
 
         if (canFarmersDiet) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.6"), LocaleLoader.getString("Herbalism.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.6"), LocaleLoader.getString("Herbalism.Effect.7")));
         }
 
         if (hasHylianLuck) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.10"), LocaleLoader.getString("Herbalism.Effect.11")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.10"), LocaleLoader.getString("Herbalism.Effect.11")));
         }
 
         if (canShroomThumb) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.12"), LocaleLoader.getString("Herbalism.Effect.13")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.12"), LocaleLoader.getString("Herbalism.Effect.13")));
         }
 
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.8"), LocaleLoader.getString("Herbalism.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Herbalism.Effect.8"), LocaleLoader.getString("Herbalism.Effect.9")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canGreenTerra || canDoubleDrop || canFarmersDiet || canGreenThumbBlocks || canGreenThumbPlants || canShroomThumb;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canGreenTerra) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.GTe.Length", greenTerraLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", greenTerraLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.GTe.Length", greenTerraLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", greenTerraLengthEndurance) : ""));
         }
 
         if (canGreenThumbBlocks || canGreenThumbPlants) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.GTh.Chance", greenThumbChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", greenThumbChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.GTh.Chance", greenThumbChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", greenThumbChanceLucky) : ""));
         }
 
         if (canGreenThumbPlants) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.GTh.Stage", greenThumbStage));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.GTh.Stage", greenThumbStage));
         }
 
         if (canFarmersDiet) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.FD", farmersDietRank));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.FD", farmersDietRank));
         }
 
         if (hasHylianLuck) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.HylianLuck", hylianLuckChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", hylianLuckChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.HylianLuck", hylianLuckChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", hylianLuckChanceLucky) : ""));
         }
 
         if (canShroomThumb) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.ShroomThumb.Chance", shroomThumbChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shroomThumbChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.ShroomThumb.Chance", shroomThumbChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", shroomThumbChanceLucky) : ""));
         }
 
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Herbalism.Ability.DoubleDropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Herbalism.Ability.DoubleDropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
         }
+
+        return messages;
     }
 }

+ 32 - 30
src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -7,6 +12,7 @@ import com.gmail.nossr50.skills.mining.BlastMining.Tier;
 import com.gmail.nossr50.skills.mining.Mining;
 import com.gmail.nossr50.skills.mining.MiningManager;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
 
 public class MiningCommand extends SkillCommand {
     private String doubleDropChance;
@@ -32,24 +38,24 @@ public class MiningCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // SUPER BREAKER
         if (canSuperBreaker) {
-            String[] superBreakerStrings = calculateLengthDisplayValues();
+            String[] superBreakerStrings = calculateLengthDisplayValues(player, skillValue);
             superBreakerLength = superBreakerStrings[0];
             superBreakerLengthEndurance = superBreakerStrings[1];
         }
 
         // DOUBLE DROPS
         if (canDoubleDrop) {
-            String[] doubleDropStrings = calculateAbilityDisplayValues(Mining.doubleDropsMaxLevel, Mining.doubleDropsMaxChance);
+            String[] doubleDropStrings = calculateAbilityDisplayValues(skillValue, Mining.doubleDropsMaxLevel, Mining.doubleDropsMaxChance, isLucky);
             doubleDropChance = doubleDropStrings[0];
             doubleDropChanceLucky = doubleDropStrings[1];
         }
 
         // BLAST MINING
         if (canBlast || canDemoExpert || canBiggerBombs) {
-            MiningManager miningManager = mcMMOPlayer.getMiningManager();
+            MiningManager miningManager = UserManager.getPlayer(player).getMiningManager();
 
             blastMiningRank = miningManager.getBlastMiningTier();
             bonusTNTDrops = miningManager.getDropMultiplier();
@@ -61,7 +67,7 @@ public class MiningCommand extends SkillCommand {
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canBiggerBombs = Permissions.biggerBombs(player);
         canBlast = Permissions.remoteDetonation(player);
         canDemoExpert = Permissions.demolitionsExpertise(player);
@@ -70,58 +76,52 @@ public class MiningCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canBiggerBombs || canBlast || canDemoExpert || canDoubleDrop || canSuperBreaker;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canSuperBreaker) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.0"), LocaleLoader.getString("Mining.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.0"), LocaleLoader.getString("Mining.Effect.1")));
         }
 
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.2"), LocaleLoader.getString("Mining.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.2"), LocaleLoader.getString("Mining.Effect.3")));
         }
 
         if (canBlast) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.4"), LocaleLoader.getString("Mining.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.4"), LocaleLoader.getString("Mining.Effect.5")));
         }
 
         if (canBiggerBombs) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.6"), LocaleLoader.getString("Mining.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.6"), LocaleLoader.getString("Mining.Effect.7")));
         }
 
         if (canDemoExpert) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.8"), LocaleLoader.getString("Mining.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Mining.Effect.8"), LocaleLoader.getString("Mining.Effect.9")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canBiggerBombs || canBlast || canDemoExpert || canDoubleDrop || canSuperBreaker;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Mining.Effect.DropChance", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
         }
 
         if (canSuperBreaker) {
-            player.sendMessage(LocaleLoader.getString("Mining.Ability.Length", superBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", superBreakerLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Mining.Ability.Length", superBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", superBreakerLengthEndurance) : ""));
         }
 
         if (canBlast) {
             int unlockLevel = AdvancedConfig.getInstance().getBlastMiningRankLevel(Tier.ONE);
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.0", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.0", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Mining.Blast.Rank", blastMiningRank, Tier.EIGHT.toNumerical(), LocaleLoader.getString("Mining.Blast.Effect", oreBonus, debrisReduction, bonusTNTDrops)));
+                messages.add(LocaleLoader.getString("Mining.Blast.Rank", blastMiningRank, Tier.EIGHT.toNumerical(), LocaleLoader.getString("Mining.Blast.Effect", oreBonus, debrisReduction, bonusTNTDrops)));
             }
         }
 
@@ -129,10 +129,10 @@ public class MiningCommand extends SkillCommand {
             int unlockLevel = AdvancedConfig.getInstance().getBlastMiningRankLevel(Tier.TWO);
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.1", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.1", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Mining.Blast.Radius.Increase", blastRadiusIncrease));
+                messages.add(LocaleLoader.getString("Mining.Blast.Radius.Increase", blastRadiusIncrease));
             }
         }
 
@@ -140,11 +140,13 @@ public class MiningCommand extends SkillCommand {
             int unlockLevel = AdvancedConfig.getInstance().getBlastMiningRankLevel(Tier.FOUR);
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.2", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Mining.Ability.Locked.2", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease));
+                messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease));
             }
         }
+
+        return messages;
     }
 }

+ 33 - 30
src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java

@@ -1,6 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.bukkit.Material;
+import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.datatypes.skills.SkillType;
@@ -11,6 +15,7 @@ import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.skills.repair.RepairManager;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
 
 public class RepairCommand extends SkillCommand {
     private String repairMasteryBonus;
@@ -40,7 +45,7 @@ public class RepairCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // We're using pickaxes here, not the best but it works
         Repairable diamondRepairable = mcMMO.getRepairableManager().getRepairable(Material.DIAMOND_PICKAXE);
         Repairable goldRepairable = mcMMO.getRepairableManager().getRepairable(Material.GOLD_PICKAXE);
@@ -60,14 +65,14 @@ public class RepairCommand extends SkillCommand {
 
         // SUPER REPAIR
         if (canSuperRepair) {
-            String[] superRepairStrings = calculateAbilityDisplayValues(Repair.superRepairMaxBonusLevel, Repair.superRepairMaxChance);
+            String[] superRepairStrings = calculateAbilityDisplayValues(skillValue, Repair.superRepairMaxBonusLevel, Repair.superRepairMaxChance, isLucky);
             superRepairChance = superRepairStrings[0];
             superRepairChanceLucky = superRepairStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canSuperRepair = Permissions.superRepair(player);
         canMasterRepair = Permissions.repairMastery(player);
         canArcaneForge = Permissions.arcaneForging(player);
@@ -83,78 +88,76 @@ public class RepairCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canArcaneForge || canSalvage || canRepairDiamond || canRepairGold || canRepairIron || canMasterRepair || canRepairStone || canSuperRepair || canRepairString || canRepairWood || canRepairLeather;
-    }
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
-
-        player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.0"), LocaleLoader.getString("Repair.Effect.1")));
+        if (canRepairLeather || canRepairString || canRepairWood || canRepairStone || canRepairIron || canRepairGold || canRepairDiamond) {
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.0"), LocaleLoader.getString("Repair.Effect.1")));
+        }
 
         if (canMasterRepair) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.2"), LocaleLoader.getString("Repair.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.2"), LocaleLoader.getString("Repair.Effect.3")));
         }
 
         if (canSuperRepair) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.4"), LocaleLoader.getString("Repair.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.4"), LocaleLoader.getString("Repair.Effect.5")));
         }
 
         /* Repair Level Requirements */
 
         if (canRepairStone && stoneLevel > 0) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.14", stoneLevel), LocaleLoader.getString("Repair.Effect.15")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.14", stoneLevel), LocaleLoader.getString("Repair.Effect.15")));
         }
 
         if (canRepairIron && ironLevel > 0) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.12", ironLevel), LocaleLoader.getString("Repair.Effect.13")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.12", ironLevel), LocaleLoader.getString("Repair.Effect.13")));
         }
 
         if (canRepairGold && goldLevel > 0) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.10", goldLevel), LocaleLoader.getString("Repair.Effect.11")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.10", goldLevel), LocaleLoader.getString("Repair.Effect.11")));
         }
 
         if (canRepairDiamond && diamondLevel > 0) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.6", diamondLevel), LocaleLoader.getString("Repair.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.6", diamondLevel), LocaleLoader.getString("Repair.Effect.7")));
         }
 
         if (canSalvage && Repair.salvageUnlockLevel > 0) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.16", Repair.salvageUnlockLevel), LocaleLoader.getString("Repair.Effect.17")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.16", Repair.salvageUnlockLevel), LocaleLoader.getString("Repair.Effect.17")));
         }
 
         if (canArcaneForge) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.8"), LocaleLoader.getString("Repair.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Repair.Effect.8"), LocaleLoader.getString("Repair.Effect.9")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canArcaneForge || canMasterRepair || canSuperRepair;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canMasterRepair) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.Mastery", repairMasteryBonus));
+            messages.add(LocaleLoader.getString("Repair.Skills.Mastery", repairMasteryBonus));
         }
 
         if (canSuperRepair) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.Super.Chance", superRepairChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", superRepairChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Repair.Skills.Super.Chance", superRepairChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", superRepairChanceLucky) : ""));
         }
 
         if (canArcaneForge) {
-            RepairManager repairManager = mcMMOPlayer.getRepairManager();
+            RepairManager repairManager = UserManager.getPlayer(player).getRepairManager();
 
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Rank", repairManager.getArcaneForgingRank(), Tier.EIGHT.toNumerical()));
+            messages.add(LocaleLoader.getString("Repair.Arcane.Rank", repairManager.getArcaneForgingRank(), Tier.EIGHT.toNumerical()));
 
             if (ArcaneForging.arcaneForgingEnchantLoss) {
-                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Success", (arcaneBypass ? 100 : repairManager.getKeepEnchantChance())));
+                messages.add(LocaleLoader.getString("Repair.Arcane.Chance.Success", (arcaneBypass ? 100 : repairManager.getKeepEnchantChance())));
             }
 
             if (ArcaneForging.arcaneForgingDowngrades) {
-                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Downgrade", (arcaneBypass ? 0 : repairManager.getDowngradeEnchantChance())));
+                messages.add(LocaleLoader.getString("Repair.Arcane.Chance.Downgrade", (arcaneBypass ? 0 : repairManager.getDowngradeEnchantChance())));
             }
         }
+
+        return messages;
     }
 }

+ 36 - 41
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -27,14 +27,7 @@ import com.google.common.collect.ImmutableList;
 
 public abstract class SkillCommand implements TabExecutor {
     protected SkillType skill;
-    protected String skillName;
-
-    protected Player player;
-    protected McMMOPlayer mcMMOPlayer;
-
-    protected float skillValue;
-    protected boolean isLucky;
-    protected boolean hasEndurance;
+    private String skillName;
 
     protected DecimalFormat percent = new DecimalFormat("##0.00%");
     protected DecimalFormat decimal = new DecimalFormat("##0.00");
@@ -53,17 +46,17 @@ public abstract class SkillCommand implements TabExecutor {
             return true;
         }
 
-        player = (Player) sender;
-        mcMMOPlayer = UserManager.getPlayer(player);
-
         switch (args.length) {
             case 0:
-                skillValue = mcMMOPlayer.getSkillLevel(skill);
-                isLucky = Permissions.lucky(sender, skill);
-                hasEndurance = (PerksUtils.handleActivationPerks(player, 0, 0) != 0);
+                Player player = (Player) sender;
+                McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
 
-                permissionsCheck();
-                dataCalculations();
+                boolean isLucky = Permissions.lucky(player, skill);
+                boolean hasEndurance = (PerksUtils.handleActivationPerks(player, 0, 0) != 0);
+                float skillValue = mcMMOPlayer.getSkillLevel(skill);
+
+                permissionsCheck(player);
+                dataCalculations(player, skillValue, isLucky);
 
                 if (Config.getInstance().getSkillUseBoard()) {
                     ScoreboardManager.enablePlayerSkillScoreboard(player, skill);
@@ -87,17 +80,30 @@ public abstract class SkillCommand implements TabExecutor {
                     }
                 }
 
-                if (effectsHeaderPermissions()) {
+                List<String> effectMessages = effectsDisplay();
+
+                if (!effectMessages.isEmpty()) {
                     player.sendMessage(LocaleLoader.getString("Skills.Header", LocaleLoader.getString("Effects.Effects")));
+
+                    if (isLucky) {
+                        String perkPrefix = LocaleLoader.getString("MOTD.PerksPrefix");
+                        player.sendMessage(perkPrefix + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.Lucky.Name"), LocaleLoader.getString("Perks.Lucky.Desc", skillName)));
+                    }
+
+                    for (String message : effectMessages) {
+                        player.sendMessage(message);
+                    }
                 }
 
-                effectsDisplay();
+                List<String> statsMessages = statsDisplay(player, skillValue, hasEndurance, isLucky);
 
-                if (statsHeaderPermissions()) {
+                if (!statsMessages.isEmpty()) {
                     player.sendMessage(LocaleLoader.getString("Skills.Header", LocaleLoader.getString("Commands.Stats.Self")));
-                }
 
-                statsDisplay();
+                    for (String message : statsMessages) {
+                        player.sendMessage(message);
+                    }
+                }
 
                 player.sendMessage(LocaleLoader.getString("Guides.Available", skillName, skillName.toLowerCase()));
                 return true;
@@ -117,11 +123,11 @@ public abstract class SkillCommand implements TabExecutor {
         }
     }
 
-    protected int calculateRank(int maxLevel, int rankChangeLevel) {
+    protected int calculateRank(float skillValue, int maxLevel, int rankChangeLevel) {
         return Math.min((int) skillValue, maxLevel) / rankChangeLevel;
     }
 
-    protected String[] calculateAbilityDisplayValues(double chance) {
+    protected String[] calculateAbilityDisplayValues(double chance, boolean isLucky) {
         String[] displayValues = new String[2];
 
         displayValues[0] = percent.format(Math.min(chance, 100.0D) / 100.0D);
@@ -130,11 +136,11 @@ public abstract class SkillCommand implements TabExecutor {
         return displayValues;
     }
 
-    protected String[] calculateAbilityDisplayValues(int maxBonusLevel, double maxChance) {
-        return calculateAbilityDisplayValues((maxChance / maxBonusLevel) * Math.min(skillValue, maxBonusLevel));
+    protected String[] calculateAbilityDisplayValues(float skillValue, int maxBonusLevel, double maxChance, boolean isLucky) {
+        return calculateAbilityDisplayValues((maxChance / maxBonusLevel) * Math.min(skillValue, maxBonusLevel), isLucky);
     }
 
-    protected String[] calculateLengthDisplayValues() {
+    protected String[] calculateLengthDisplayValues(Player player, float skillValue) {
         int maxLength = skill.getAbility().getMaxLength();
         int length = 2 + (int) (skillValue / AdvancedConfig.getInstance().getAbilityLength());
         int enduranceLength = PerksUtils.handleActivationPerks(player, length, maxLength);
@@ -146,22 +152,11 @@ public abstract class SkillCommand implements TabExecutor {
         return new String[] { String.valueOf(length), String.valueOf(enduranceLength) };
     }
 
-    protected void luckyEffectsDisplay() {
-        if (isLucky) {
-            String perkPrefix = LocaleLoader.getString("MOTD.PerksPrefix");
-            player.sendMessage(perkPrefix + LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Perks.Lucky.Name"), LocaleLoader.getString("Perks.Lucky.Desc", skillName)));
-        }
-    }
-
-    protected abstract void dataCalculations();
-
-    protected abstract void permissionsCheck();
-
-    protected abstract boolean effectsHeaderPermissions();
+    protected abstract void dataCalculations(Player player, float skillValue, boolean isLucky);
 
-    protected abstract void effectsDisplay();
+    protected abstract void permissionsCheck(Player player);
 
-    protected abstract boolean statsHeaderPermissions();
+    protected abstract List<String> effectsDisplay();
 
-    protected abstract void statsDisplay();
+    protected abstract List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky);
 }

+ 9 - 11
src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java

@@ -15,13 +15,11 @@ public class SkillGuideCommand implements CommandExecutor {
     private String header;
     private ArrayList<String> guide;
 
-    private String invalidPage;
+    private String invalidPage = LocaleLoader.getString("Guides.Page.Invalid");
 
-    public SkillGuideCommand(SkillType skillType) {
-        header = LocaleLoader.getString("Guides.Header", skillType.getName());
-        guide = getGuide(skillType);
-
-        invalidPage = LocaleLoader.getString("Guides.Page.Invalid");
+    public SkillGuideCommand(SkillType skill) {
+        header = LocaleLoader.getString("Guides.Header", skill.getName());
+        guide = getGuide(skill);
     }
 
     @Override
@@ -68,8 +66,8 @@ public class SkillGuideCommand implements CommandExecutor {
         }
     }
 
-    private ArrayList<String> grabPageContents(int pagenum) {
-        int pageIndexStart = 8 * (pagenum - 1); // Determine what string to start at
+    private ArrayList<String> grabPageContents(int page) {
+        int pageIndexStart = 8 * (page - 1); // Determine what string to start at
         ArrayList<String> allStrings = new ArrayList<String>();
 
         allStrings.add(header);
@@ -84,15 +82,15 @@ public class SkillGuideCommand implements CommandExecutor {
             }
         }
 
-        allStrings.add("Page " + pagenum + " of " + getTotalPageNumber());
+        allStrings.add("Page " + page + " of " + getTotalPageNumber());
         return allStrings;
     }
 
-    private ArrayList<String> getGuide(SkillType skillType) {
+    private ArrayList<String> getGuide(SkillType skill) {
         ArrayList<String> guide = new ArrayList<String>();
 
         for (int i = 0; i < 10; i++) {
-            String[] section = LocaleLoader.getString("Guides." + StringUtils.getCapitalized(skillType.toString()) + ".Section." + i).split("\n");
+            String[] section = LocaleLoader.getString("Guides." + StringUtils.getCapitalized(skill.toString()) + ".Section." + i).split("\n");
 
             if (section[0].startsWith("!")) {
                 break;

+ 28 - 26
src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java

@@ -1,11 +1,17 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.smelting.Smelting;
 import com.gmail.nossr50.skills.smelting.Smelting.Tier;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
 
 public class SmeltingCommand extends SkillCommand {
     private String burnTimeModifier;
@@ -24,7 +30,7 @@ public class SmeltingCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // FUEL EFFICIENCY
         if (canFuelEfficiency) {
             burnTimeModifier = decimal.format(1 + ((skillValue / Smelting.burnModifierMaxLevel) * Smelting.burnTimeMultiplier));
@@ -32,21 +38,21 @@ public class SmeltingCommand extends SkillCommand {
 
         // SECOND SMELT
         if (canSecondSmelt) {
-            String[] secondSmeltStrings = calculateAbilityDisplayValues(Smelting.secondSmeltMaxLevel, Smelting.secondSmeltMaxChance);
+            String[] secondSmeltStrings = calculateAbilityDisplayValues(skillValue, Smelting.secondSmeltMaxLevel, Smelting.secondSmeltMaxChance, isLucky);
             secondSmeltChance = secondSmeltStrings[0];
             secondSmeltChanceLucky = secondSmeltStrings[1];
         }
 
         // FLUX MINING
         if (canFluxMine) {
-            String[] fluxMiningStrings = calculateAbilityDisplayValues(Smelting.fluxMiningChance);
+            String[] fluxMiningStrings = calculateAbilityDisplayValues(Smelting.fluxMiningChance, isLucky);
             fluxMiningChance = fluxMiningStrings[0];
             fluxMiningChanceLucky = fluxMiningStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canFuelEfficiency = Permissions.fuelEfficiency(player);
         canSecondSmelt = Permissions.doubleDrops(player, skill);
         canFluxMine = Permissions.fluxMining(player);
@@ -54,64 +60,60 @@ public class SmeltingCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canFluxMine || canFuelEfficiency || canSecondSmelt || canVanillaXPBoost;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canFuelEfficiency) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.0"), LocaleLoader.getString("Smelting.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.0"), LocaleLoader.getString("Smelting.Effect.1")));
         }
 
         if (canSecondSmelt) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.2"), LocaleLoader.getString("Smelting.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.2"), LocaleLoader.getString("Smelting.Effect.3")));
         }
 
         if (canVanillaXPBoost) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.4"), LocaleLoader.getString("Smelting.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.4"), LocaleLoader.getString("Smelting.Effect.5")));
         }
 
         if (canFluxMine) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.6"), LocaleLoader.getString("Smelting.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Smelting.Effect.6"), LocaleLoader.getString("Smelting.Effect.7")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canFluxMine || canFuelEfficiency || canSecondSmelt || canVanillaXPBoost;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canFuelEfficiency) {
-            player.sendMessage(LocaleLoader.getString("Smelting.Ability.FuelEfficiency", burnTimeModifier));
+            messages.add(LocaleLoader.getString("Smelting.Ability.FuelEfficiency", burnTimeModifier));
         }
 
         if (canSecondSmelt) {
-            player.sendMessage(LocaleLoader.getString("Smelting.Ability.SecondSmelt", secondSmeltChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", secondSmeltChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Smelting.Ability.SecondSmelt", secondSmeltChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", secondSmeltChanceLucky) : ""));
         }
 
         if (canVanillaXPBoost) {
             int unlockLevel = AdvancedConfig.getInstance().getSmeltingRankLevel(Tier.ONE);
 
             if (skillValue < unlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Smelting.Ability.Locked.0", unlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Smelting.Ability.Locked.0", unlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Smelting.Ability.VanillaXPBoost", mcMMOPlayer.getSmeltingManager().getVanillaXpMultiplier()));
+                messages.add(LocaleLoader.getString("Smelting.Ability.VanillaXPBoost", UserManager.getPlayer(player).getSmeltingManager().getVanillaXpMultiplier()));
             }
         }
 
         if (canFluxMine) {
             if (skillValue < Smelting.fluxMiningUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Smelting.Ability.Locked.1", Smelting.fluxMiningUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Smelting.Ability.Locked.1", Smelting.fluxMiningUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Smelting.Ability.FluxMining", fluxMiningChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", fluxMiningChanceLucky) : ""));
+                messages.add(LocaleLoader.getString("Smelting.Ability.FluxMining", fluxMiningChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", fluxMiningChanceLucky) : ""));
             }
         }
+
+        return messages;
     }
 }

+ 27 - 26
src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.swords.Swords;
@@ -23,10 +28,10 @@ public class SwordsCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // SERRATED STRIKES
         if (canSerratedStrike) {
-            String[] serratedStrikesStrings = calculateLengthDisplayValues();
+            String[] serratedStrikesStrings = calculateLengthDisplayValues(player, skillValue);
             serratedStrikesLength = serratedStrikesStrings[0];
             serratedStrikesLengthEndurance = serratedStrikesStrings[1];
         }
@@ -35,68 +40,64 @@ public class SwordsCommand extends SkillCommand {
         if (canBleed) {
             bleedLength = (skillValue >= Swords.bleedMaxBonusLevel) ? Swords.bleedMaxTicks : Swords.bleedBaseTicks;
 
-            String[] bleedStrings = calculateAbilityDisplayValues(Swords.bleedMaxBonusLevel, Swords.bleedMaxChance);
+            String[] bleedStrings = calculateAbilityDisplayValues(skillValue, Swords.bleedMaxBonusLevel, Swords.bleedMaxChance, isLucky);
             bleedChance = bleedStrings[0];
             bleedChanceLucky = bleedStrings[1];
         }
 
         // COUNTER ATTACK
         if (canCounter) {
-            String[] counterAttackStrings = calculateAbilityDisplayValues(Swords.counterAttackMaxBonusLevel, Swords.counterAttackMaxChance);
+            String[] counterAttackStrings = calculateAbilityDisplayValues(skillValue, Swords.counterAttackMaxBonusLevel, Swords.counterAttackMaxChance, isLucky);
             counterAttackChance = counterAttackStrings[0];
             counterAttackChanceLucky = counterAttackStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canBleed = Permissions.bleed(player);
         canCounter = Permissions.counterAttack(player);
         canSerratedStrike = Permissions.serratedStrikes(player);
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canBleed || canCounter || canSerratedStrike;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canCounter) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.0"), LocaleLoader.getString("Swords.Effect.1", percent.format(1.0D / Swords.counterAttackModifier))));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.0"), LocaleLoader.getString("Swords.Effect.1", percent.format(1.0D / Swords.counterAttackModifier))));
         }
 
         if (canSerratedStrike) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.2"), LocaleLoader.getString("Swords.Effect.3", percent.format(1.0D / Swords.serratedStrikesModifier))));
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.4"), LocaleLoader.getString("Swords.Effect.5", Swords.serratedStrikesBleedTicks)));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.2"), LocaleLoader.getString("Swords.Effect.3", percent.format(1.0D / Swords.serratedStrikesModifier))));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.4"), LocaleLoader.getString("Swords.Effect.5", Swords.serratedStrikesBleedTicks)));
         }
 
         if (canBleed) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.6"), LocaleLoader.getString("Swords.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Swords.Effect.6"), LocaleLoader.getString("Swords.Effect.7")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canBleed || canCounter || canSerratedStrike;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canCounter) {
-            player.sendMessage(LocaleLoader.getString("Swords.Combat.Counter.Chance", counterAttackChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", counterAttackChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Swords.Combat.Counter.Chance", counterAttackChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", counterAttackChanceLucky) : ""));
         }
 
         if (canBleed) {
-            player.sendMessage(LocaleLoader.getString("Swords.Combat.Bleed.Length", bleedLength));
-            player.sendMessage(LocaleLoader.getString("Swords.Combat.Bleed.Note"));
-            player.sendMessage(LocaleLoader.getString("Swords.Combat.Bleed.Chance", bleedChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", bleedChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Swords.Combat.Bleed.Length", bleedLength));
+            messages.add(LocaleLoader.getString("Swords.Combat.Bleed.Note"));
+            messages.add(LocaleLoader.getString("Swords.Combat.Bleed.Chance", bleedChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", bleedChanceLucky) : ""));
         }
 
         if (canSerratedStrike) {
-            player.sendMessage(LocaleLoader.getString("Swords.SS.Length", serratedStrikesLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Swords.SS.Length", serratedStrikesLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : ""));
         }
+
+        return messages;
     }
 }

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

@@ -1,6 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.skills.SkillType;
@@ -27,16 +31,16 @@ public class TamingCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         if (canGore) {
-            String[] goreStrings = calculateAbilityDisplayValues(Taming.goreMaxBonusLevel, Taming.goreMaxChance);
+            String[] goreStrings = calculateAbilityDisplayValues(skillValue, Taming.goreMaxBonusLevel, Taming.goreMaxChance, isLucky);
             goreChance = goreStrings[0];
             goreChanceLucky = goreStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canBeastLore = Permissions.beastLore(player);
         canCallWild = Permissions.callOfTheWild(player, EntityType.HORSE) || Permissions.callOfTheWild(player, EntityType.WOLF) || Permissions.callOfTheWild(player, EntityType.OCELOT);
         canEnvironmentallyAware = Permissions.environmentallyAware(player);
@@ -49,117 +53,113 @@ public class TamingCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canBeastLore || canCallWild || canEnvironmentallyAware || canFastFood || canGore || canSharpenedClaws || canShockProof || canThickFur || canHolyHound;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canBeastLore) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.0"), LocaleLoader.getString("Taming.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.0"), LocaleLoader.getString("Taming.Effect.1")));
         }
 
         if (canGore) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.2"), LocaleLoader.getString("Taming.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.2"), LocaleLoader.getString("Taming.Effect.3")));
         }
 
         if (canSharpenedClaws) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.4"), LocaleLoader.getString("Taming.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.4"), LocaleLoader.getString("Taming.Effect.5")));
         }
 
         if (canEnvironmentallyAware) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.6"), LocaleLoader.getString("Taming.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.6"), LocaleLoader.getString("Taming.Effect.7")));
         }
 
         if (canThickFur) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.8"), LocaleLoader.getString("Taming.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.8"), LocaleLoader.getString("Taming.Effect.9")));
         }
 
         if (canShockProof) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.10"), LocaleLoader.getString("Taming.Effect.11")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.10"), LocaleLoader.getString("Taming.Effect.11")));
         }
 
         if (canFastFood) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.16"), LocaleLoader.getString("Taming.Effect.17")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.16"), LocaleLoader.getString("Taming.Effect.17")));
         }
 
         if (canHolyHound) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.18"), LocaleLoader.getString("Taming.Effect.19")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.18"), LocaleLoader.getString("Taming.Effect.19")));
         }
 
         if (canCallWild) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.12"), LocaleLoader.getString("Taming.Effect.13")));
-            player.sendMessage(LocaleLoader.getString("Taming.Effect.14", Config.getInstance().getTamingCOTWOcelotCost()));
-            player.sendMessage(LocaleLoader.getString("Taming.Effect.15", Config.getInstance().getTamingCOTWWolfCost()));
-            player.sendMessage(LocaleLoader.getString("Taming.Effect.20", Config.getInstance().getTamingCOTWHorseCost()));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Taming.Effect.12"), LocaleLoader.getString("Taming.Effect.13")));
+            messages.add(LocaleLoader.getString("Taming.Effect.14", Config.getInstance().getTamingCOTWOcelotCost()));
+            messages.add(LocaleLoader.getString("Taming.Effect.15", Config.getInstance().getTamingCOTWWolfCost()));
+            messages.add(LocaleLoader.getString("Taming.Effect.20", Config.getInstance().getTamingCOTWHorseCost()));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canEnvironmentallyAware || canFastFood || canGore || canSharpenedClaws || canShockProof || canThickFur || canHolyHound;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canFastFood) {
             if (skillValue < Taming.fastFoodServiceUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.4", Taming.fastFoodServiceUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.4", Taming.fastFoodServiceUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.8"), LocaleLoader.getString("Taming.Ability.Bonus.9", percent.format(Taming.fastFoodServiceActivationChance / 100D))));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.8"), LocaleLoader.getString("Taming.Ability.Bonus.9", percent.format(Taming.fastFoodServiceActivationChance / 100D))));
             }
         }
 
         if (canEnvironmentallyAware) {
             if (skillValue < Taming.environmentallyAwareUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.0", Taming.environmentallyAwareUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.0", Taming.environmentallyAwareUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.0"), LocaleLoader.getString("Taming.Ability.Bonus.1")));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.0"), LocaleLoader.getString("Taming.Ability.Bonus.1")));
             }
         }
 
         if (canThickFur) {
             if (skillValue < Taming.thickFurUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.1", Taming.thickFurUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.1", Taming.thickFurUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.2"), LocaleLoader.getString("Taming.Ability.Bonus.3", Taming.thickFurModifier)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.2"), LocaleLoader.getString("Taming.Ability.Bonus.3", Taming.thickFurModifier)));
             }
         }
 
         if (canHolyHound) {
             if (skillValue < Taming.holyHoundUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.5", Taming.holyHoundUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.5", Taming.holyHoundUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.10"), LocaleLoader.getString("Taming.Ability.Bonus.11")));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.10"), LocaleLoader.getString("Taming.Ability.Bonus.11")));
             }
         }
 
         if (canShockProof) {
             if (skillValue < Taming.shockProofUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.2", Taming.shockProofUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.2", Taming.shockProofUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.4"), LocaleLoader.getString("Taming.Ability.Bonus.5", Taming.shockProofModifier)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.4"), LocaleLoader.getString("Taming.Ability.Bonus.5", Taming.shockProofModifier)));
             }
         }
 
         if (canSharpenedClaws) {
             if (skillValue < Taming.sharpenedClawsUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.3", Taming.sharpenedClawsUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Taming.Ability.Locked.3", Taming.sharpenedClawsUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.6"), LocaleLoader.getString("Taming.Ability.Bonus.7", Taming.sharpenedClawsBonusDamage)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Taming.Ability.Bonus.6"), LocaleLoader.getString("Taming.Ability.Bonus.7", Taming.sharpenedClawsBonusDamage)));
             }
         }
 
         if (canGore) {
-            player.sendMessage(LocaleLoader.getString("Taming.Combat.Chance.Gore", goreChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", goreChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Taming.Combat.Chance.Gore", goreChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", goreChanceLucky) : ""));
         }
+
+        return messages;
     }
 }

+ 29 - 28
src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.unarmed.Unarmed;
@@ -27,24 +32,24 @@ public class UnarmedCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // BERSERK
         if (canBerserk) {
-            String[] berserkStrings = calculateLengthDisplayValues();
+            String[] berserkStrings = calculateLengthDisplayValues(player, skillValue);
             berserkLength = berserkStrings[0];
             berserkLengthEndurance = berserkStrings[1];
         }
 
         // DISARM
         if (canDisarm) {
-            String[] disarmStrings = calculateAbilityDisplayValues(Unarmed.disarmMaxBonusLevel, Unarmed.disarmMaxChance);
+            String[] disarmStrings = calculateAbilityDisplayValues(skillValue, Unarmed.disarmMaxBonusLevel, Unarmed.disarmMaxChance, isLucky);
             disarmChance = disarmStrings[0];
             disarmChanceLucky = disarmStrings[1];
         }
 
         // DEFLECT
         if (canDeflect) {
-            String[] deflectStrings = calculateAbilityDisplayValues(Unarmed.deflectMaxBonusLevel, Unarmed.deflectMaxChance);
+            String[] deflectStrings = calculateAbilityDisplayValues(skillValue, Unarmed.deflectMaxBonusLevel, Unarmed.deflectMaxChance, isLucky);
             deflectChance = deflectStrings[0];
             deflectChanceLucky = deflectStrings[1];
         }
@@ -56,14 +61,14 @@ public class UnarmedCommand extends SkillCommand {
 
         // IRON GRIP
         if (canIronGrip) {
-            String[] ironGripStrings = calculateAbilityDisplayValues(Unarmed.ironGripMaxBonusLevel, Unarmed.ironGripMaxChance);
+            String[] ironGripStrings = calculateAbilityDisplayValues(skillValue, Unarmed.ironGripMaxBonusLevel, Unarmed.ironGripMaxChance, isLucky);
             ironGripChance = ironGripStrings[0];
             ironGripChanceLucky = ironGripStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canBerserk = Permissions.berserk(player);
         canBonusDamage = Permissions.bonusDamage(player, skill);
         canDeflect = Permissions.arrowDeflect(player);
@@ -72,60 +77,56 @@ public class UnarmedCommand extends SkillCommand {
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canBerserk || canBonusDamage || canDeflect || canDisarm || canIronGrip;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canBerserk) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.0"), LocaleLoader.getString("Unarmed.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.0"), LocaleLoader.getString("Unarmed.Effect.1")));
         }
 
         if (canDisarm) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.2"), LocaleLoader.getString("Unarmed.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.2"), LocaleLoader.getString("Unarmed.Effect.3")));
         }
 
         if (canBonusDamage) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.4"), LocaleLoader.getString("Unarmed.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.4"), LocaleLoader.getString("Unarmed.Effect.5")));
         }
 
         if (canDeflect) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.6"), LocaleLoader.getString("Unarmed.Effect.7")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.6"), LocaleLoader.getString("Unarmed.Effect.7")));
         }
 
         if (canIronGrip) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.8"), LocaleLoader.getString("Unarmed.Effect.9")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Unarmed.Effect.8"), LocaleLoader.getString("Unarmed.Effect.9")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canBerserk || canBonusDamage || canDeflect || canDisarm || canIronGrip;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canBonusDamage) {
-            player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Unarmed.Ability.Bonus.0"), LocaleLoader.getString("Unarmed.Ability.Bonus.1", ironArmBonus)));
+            messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Unarmed.Ability.Bonus.0"), LocaleLoader.getString("Unarmed.Ability.Bonus.1", ironArmBonus)));
         }
 
         if (canDeflect) {
-            player.sendMessage(LocaleLoader.getString("Unarmed.Ability.Chance.ArrowDeflect", deflectChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", deflectChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.ArrowDeflect", deflectChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", deflectChanceLucky) : ""));
         }
 
         if (canDisarm) {
-            player.sendMessage(LocaleLoader.getString("Unarmed.Ability.Chance.Disarm", disarmChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", disarmChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.Disarm", disarmChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", disarmChanceLucky) : ""));
         }
 
         if (canIronGrip) {
-            player.sendMessage(LocaleLoader.getString("Unarmed.Ability.Chance.IronGrip", ironGripChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.IronGrip", ironGripChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) : ""));
         }
 
         if (canBerserk) {
-            player.sendMessage(LocaleLoader.getString("Unarmed.Ability.Berserk.Length", berserkLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", berserkLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Unarmed.Ability.Berserk.Length", berserkLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", berserkLengthEndurance) : ""));
         }
+
+        return messages;
     }
 }

+ 24 - 23
src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java

@@ -1,5 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.entity.Player;
+
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -21,75 +26,71 @@ public class WoodcuttingCommand extends SkillCommand {
     }
 
     @Override
-    protected void dataCalculations() {
+    protected void dataCalculations(Player player, float skillValue, boolean isLucky) {
         // TREE FELLER
         if (canTreeFell) {
-            String[] treeFellerStrings = calculateLengthDisplayValues();
+            String[] treeFellerStrings = calculateLengthDisplayValues(player, skillValue);
             treeFellerLength = treeFellerStrings[0];
             treeFellerLengthEndurance = treeFellerStrings[1];
         }
 
         // DOUBLE DROPS
         if (canDoubleDrop) {
-            String[] doubleDropStrings = calculateAbilityDisplayValues(Woodcutting.doubleDropsMaxLevel, Woodcutting.doubleDropsMaxChance);
+            String[] doubleDropStrings = calculateAbilityDisplayValues(skillValue, Woodcutting.doubleDropsMaxLevel, Woodcutting.doubleDropsMaxChance, isLucky);
             doubleDropChance = doubleDropStrings[0];
             doubleDropChanceLucky = doubleDropStrings[1];
         }
     }
 
     @Override
-    protected void permissionsCheck() {
+    protected void permissionsCheck(Player player) {
         canTreeFell = Permissions.treeFeller(player);
         canDoubleDrop = Permissions.doubleDrops(player, skill) && !skill.getDoubleDropsDisabled();
         canLeafBlow = Permissions.leafBlower(player);
     }
 
     @Override
-    protected boolean effectsHeaderPermissions() {
-        return canDoubleDrop || canLeafBlow || canTreeFell;
-    }
-
-    @Override
-    protected void effectsDisplay() {
-        luckyEffectsDisplay();
+    protected List<String> effectsDisplay() {
+        List<String> messages = new ArrayList<String>();
 
         if (canTreeFell) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.0"), LocaleLoader.getString("Woodcutting.Effect.1")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.0"), LocaleLoader.getString("Woodcutting.Effect.1")));
         }
 
         if (canLeafBlow) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.2"), LocaleLoader.getString("Woodcutting.Effect.3")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.2"), LocaleLoader.getString("Woodcutting.Effect.3")));
         }
 
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.4"), LocaleLoader.getString("Woodcutting.Effect.5")));
+            messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.4"), LocaleLoader.getString("Woodcutting.Effect.5")));
         }
-    }
 
-    @Override
-    protected boolean statsHeaderPermissions() {
-        return canDoubleDrop || canLeafBlow || canTreeFell;
+        return messages;
     }
 
     @Override
-    protected void statsDisplay() {
+    protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
+        List<String> messages = new ArrayList<String>();
+
         if (canLeafBlow) {
             int leafBlowerUnlockLevel = AdvancedConfig.getInstance().getLeafBlowUnlockLevel();
 
             if (skillValue < leafBlowerUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Woodcutting.Ability.Locked.0", leafBlowerUnlockLevel)));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Woodcutting.Ability.Locked.0", leafBlowerUnlockLevel)));
             }
             else {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1")));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1")));
             }
         }
 
         if (canDoubleDrop) {
-            player.sendMessage(LocaleLoader.getString("Woodcutting.Ability.Chance.DDrop", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
+            messages.add(LocaleLoader.getString("Woodcutting.Ability.Chance.DDrop", doubleDropChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
         }
 
         if (canTreeFell) {
-            player.sendMessage(LocaleLoader.getString("Woodcutting.Ability.Length", treeFellerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", treeFellerLengthEndurance) : ""));
+            messages.add(LocaleLoader.getString("Woodcutting.Ability.Length", treeFellerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", treeFellerLengthEndurance) : ""));
         }
+
+        return messages;
     }
 }

+ 38 - 0
src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java

@@ -68,6 +68,7 @@ public class TreasureConfig extends ConfigLoader {
     private TreasureConfig() {
         super("treasures.yml");
         loadKeys();
+        validate();
     }
 
     public static TreasureConfig getInstance() {
@@ -78,6 +79,43 @@ public class TreasureConfig extends ConfigLoader {
         return instance;
     }
 
+    @Override
+    protected boolean validateKeys() {
+        // Validate all the settings!
+        List<String> reason = new ArrayList<String>();
+
+        for (String tier : config.getConfigurationSection("Enchantment_Drop_Rates").getKeys(false)) {
+            double totalEnchantDropRate = 0;
+            double totalItemDropRate = 0;
+
+            for (Rarity rarity : Rarity.values()) {
+                double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
+                double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity.toString());
+
+                if ((enchantDropRate < 0.0 || enchantDropRate > 100.0) && rarity != Rarity.TRAP && rarity != Rarity.RECORD) {
+                    reason.add("The enchant drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
+                }
+
+                if (itemDropRate < 0.0 || itemDropRate > 100.0) {
+                    reason.add("The item drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
+                }
+
+                totalEnchantDropRate += enchantDropRate;
+                totalItemDropRate += itemDropRate;
+            }
+
+            if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
+                reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
+            }
+
+            if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
+                reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
+            }
+        }
+
+        return noErrorsInConfig(reason);
+    }
+
     @Override
     protected void loadKeys() {
         if (config.getConfigurationSection("Treasures") != null) {

+ 0 - 46
src/main/java/com/gmail/nossr50/datatypes/chat/ChatMode.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.datatypes.chat;
 
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 
 public enum ChatMode {
@@ -15,51 +14,6 @@ public enum ChatMode {
         this.disabledMessage = disabledMessage;
     }
 
-    public boolean isEnabled(McMMOPlayer mcMMOPlayer) {
-        switch (this) {
-            case ADMIN:
-                return mcMMOPlayer.getAdminChatMode();
-
-            case PARTY:
-                return mcMMOPlayer.getPartyChatMode();
-
-            default:
-                return false;
-        }
-    }
-
-    public void disable(McMMOPlayer mcMMOPlayer) {
-        switch (this) {
-            case ADMIN:
-                mcMMOPlayer.setAdminChat(false);
-                return;
-
-            case PARTY:
-                mcMMOPlayer.setPartyChat(false);
-                return;
-
-            default:
-                return;
-        }
-    }
-
-    public void enable(McMMOPlayer mcMMOPlayer) {
-        switch (this) {
-            case ADMIN:
-                mcMMOPlayer.setAdminChat(true);
-                mcMMOPlayer.setPartyChat(false);
-                return;
-
-            case PARTY:
-                mcMMOPlayer.setPartyChat(true);
-                mcMMOPlayer.setAdminChat(false);
-                return;
-
-            default:
-                return;
-        }
-    }
-
     public String getEnabledMessage() {
         return enabledMessage;
     }

+ 54 - 14
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -16,6 +16,7 @@ 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.chat.ChatMode;
 import com.gmail.nossr50.datatypes.mods.CustomTool;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.PartyTeleportRecord;
@@ -641,28 +642,67 @@ public class McMMOPlayer {
      * Chat modes
      */
 
-    public boolean getAdminChatMode() {
-        return adminChatMode;
-    }
+    public boolean isChatEnabled(ChatMode mode) {
+        switch (mode) {
+            case ADMIN:
+                return adminChatMode;
 
-    public void setAdminChat(boolean enabled) {
-        adminChatMode = enabled;
-    }
+            case PARTY:
+                return partyChatMode;
 
-    public void toggleAdminChat() {
-        adminChatMode = !adminChatMode;
+            default:
+                return false;
+        }
     }
 
-    public boolean getPartyChatMode() {
-        return partyChatMode;
+    public void disableChat(ChatMode mode) {
+        switch (mode) {
+            case ADMIN:
+                adminChatMode = false;
+                return;
+
+            case PARTY:
+                partyChatMode = false;
+                return;
+
+            default:
+                return;
+        }
     }
 
-    public void setPartyChat(boolean enabled) {
-        partyChatMode = enabled;
+    public void enableChat(ChatMode mode) {
+        switch (mode) {
+            case ADMIN:
+                adminChatMode = true;
+                partyChatMode = false;
+                return;
+
+            case PARTY:
+                partyChatMode = true;
+                adminChatMode = false;
+                return;
+
+            default:
+                return;
+        }
+
     }
 
-    public void togglePartyChat() {
-        partyChatMode = !partyChatMode;
+    public void toggleChat(ChatMode mode) {
+        switch (mode) {
+            case ADMIN:
+                adminChatMode = !adminChatMode;
+                partyChatMode = adminChatMode ? false : partyChatMode;
+                return;
+
+            case PARTY:
+                partyChatMode = !partyChatMode;
+                adminChatMode = partyChatMode ? false : adminChatMode;
+                return;
+
+            default:
+                return;
+        }
     }
 
     public boolean isUsingUnarmed() {

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

@@ -167,7 +167,10 @@ public enum SkillType {
             }
         }
 
-        mcMMO.p.getLogger().warning("[Debug] Invalid mcMMO skill (" + skillName + ")");
+        if (!skillName.equalsIgnoreCase("all")) {
+            mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize
+        }
+
         return null;
     }
 

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

@@ -628,11 +628,11 @@ public class PlayerListener implements Listener {
 
         ChatManager chatManager = null;
 
-        if (mcMMOPlayer.getPartyChatMode()) {
+        if (mcMMOPlayer.isChatEnabled(ChatMode.PARTY)) {
             Party party = mcMMOPlayer.getParty();
 
             if (party == null) {
-                mcMMOPlayer.togglePartyChat();
+                mcMMOPlayer.disableChat(ChatMode.PARTY);
                 player.sendMessage(LocaleLoader.getString("Commands.Party.None"));
                 return;
             }
@@ -640,7 +640,7 @@ public class PlayerListener implements Listener {
             chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.PARTY);
             ((PartyChatManager) chatManager).setParty(party);
         }
-        else if (mcMMOPlayer.getAdminChatMode()) {
+        else if (mcMMOPlayer.isChatEnabled(ChatMode.ADMIN)) {
             chatManager = ChatManagerFactory.getChatManager(plugin, ChatMode.ADMIN);
         }
 

+ 2 - 1
src/main/java/com/gmail/nossr50/party/PartyManager.java

@@ -11,6 +11,7 @@ import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.chat.ChatMode;
 import com.gmail.nossr50.datatypes.party.ItemShareType;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.ShareMode;
@@ -494,7 +495,7 @@ public final class PartyManager {
      */
     public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) {
         mcMMOPlayer.removeParty();
-        mcMMOPlayer.setPartyChat(false);
+        mcMMOPlayer.disableChat(ChatMode.PARTY);
         mcMMOPlayer.setItemShareModifier(10);
     }
 

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

@@ -8,6 +8,7 @@ import org.bukkit.command.PluginCommand;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.commands.KrakenCommand;
 import com.gmail.nossr50.commands.McabilityCommand;
+import com.gmail.nossr50.commands.McconvertCommand;
 import com.gmail.nossr50.commands.McgodCommand;
 import com.gmail.nossr50.commands.McmmoCommand;
 import com.gmail.nossr50.commands.McnotifyCommand;
@@ -17,7 +18,6 @@ import com.gmail.nossr50.commands.MobhealthCommand;
 import com.gmail.nossr50.commands.XprateCommand;
 import com.gmail.nossr50.commands.chat.AdminChatCommand;
 import com.gmail.nossr50.commands.chat.PartyChatCommand;
-import com.gmail.nossr50.commands.database.McconvertCommand;
 import com.gmail.nossr50.commands.database.McpurgeCommand;
 import com.gmail.nossr50.commands.database.McremoveCommand;
 import com.gmail.nossr50.commands.database.MmoshowdbCommand;

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

@@ -26,7 +26,7 @@ public final class CommandUtils {
     private CommandUtils() {}
 
     public static boolean isChildSkill(CommandSender sender, SkillType skill) {
-        if (!skill.isChildSkill()) {
+        if (skill == null || !skill.isChildSkill()) {
             return false;
         }
 
@@ -134,7 +134,7 @@ public final class CommandUtils {
     }
 
     public static boolean isInvalidSkill(CommandSender sender, String skillName) {
-        if (SkillUtils.isSkill(skillName)) {
+        if (skillName.equalsIgnoreCase("all") || SkillUtils.isSkill(skillName)) {
             return false;
         }
 

+ 2 - 2
src/main/resources/locale/locale_en_US.properties

@@ -796,8 +796,8 @@ Perks.ActivationTime.Desc=Increases ability activation time by {0} seconds.
 Perks.ActivationTime.Bonus=[[GOLD]] ({0}s with Endurance Perk)
 
 #HARDCORE
-Hardcore.Mode.Disabled=[[GOLD]][mcMMO] Hardcore mode {0} disabled. {1}
-Hardcore.Mode.Enabled=[[GOLD]][mcMMO] Hardcore mode {0} enabled. {1}
+Hardcore.Mode.Disabled=[[GOLD]][mcMMO] Hardcore mode {0} disabled for {1}.
+Hardcore.Mode.Enabled=[[GOLD]][mcMMO] Hardcore mode {0} enabled for {1}.
 Hardcore.DeathStatLoss.Name=Skill Death Penalty
 Hardcore.DeathStatLoss.PlayerDeath=[[GOLD]][mcMMO] [[DARK_RED]]You have lost [[BLUE]]{0}[[DARK_RED]] levels from death.
 Hardcore.DeathStatLoss.PercentageChanged=[[GOLD]][mcMMO] The stat loss percentage was changed to {0}.