Jelajahi Sumber

Create a proper RepairManager to match the others, rename our old
RepairManager to RepairableManager.

GJ 12 tahun lalu
induk
melakukan
e5f6da01ec

+ 8 - 7
src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java

@@ -9,6 +9,7 @@ import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.skills.repair.Repairable;
 import com.gmail.nossr50.skills.repair.Salvage;
 import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
 
 public class RepairCommand extends SkillCommand {
     private int arcaneForgingRank;
@@ -41,10 +42,10 @@ public class RepairCommand extends SkillCommand {
     @Override
     protected void dataCalculations() {
         // We're using pickaxes here, not the best but it works
-        Repairable diamondRepairable = mcMMO.repairManager.getRepairable(Material.DIAMOND_PICKAXE.getId());
-        Repairable goldRepairable = mcMMO.repairManager.getRepairable(Material.GOLD_PICKAXE.getId());
-        Repairable ironRepairable = mcMMO.repairManager.getRepairable(Material.IRON_PICKAXE.getId());
-        Repairable stoneRepairable = mcMMO.repairManager.getRepairable(Material.STONE_PICKAXE.getId());
+        Repairable diamondRepairable = mcMMO.repairableManager.getRepairable(Material.DIAMOND_PICKAXE.getId());
+        Repairable goldRepairable = mcMMO.repairableManager.getRepairable(Material.GOLD_PICKAXE.getId());
+        Repairable ironRepairable = mcMMO.repairableManager.getRepairable(Material.IRON_PICKAXE.getId());
+        Repairable stoneRepairable = mcMMO.repairableManager.getRepairable(Material.STONE_PICKAXE.getId());
 
         // TODO: This isn't really accurate - if they don't have pickaxes loaded it doesn't always mean the repair level is 0
         diamondLevel = (diamondRepairable == null) ? 0 : diamondRepairable.getMinimumLevel();
@@ -66,7 +67,7 @@ public class RepairCommand extends SkillCommand {
         superRepairChanceLucky = superRepairStrings[1];
 
         // ARCANE FORGING
-        arcaneForgingRank = Repair.getArcaneForgingRank(profile);
+        arcaneForgingRank = UserManager.getPlayer(player).getRepairManager().getArcaneForgingRank();
     }
 
     @Override
@@ -155,11 +156,11 @@ public class RepairCommand extends SkillCommand {
             player.sendMessage(LocaleLoader.getString("Repair.Arcane.Rank", arcaneForgingRank));
 
             if (Repair.arcaneForgingEnchantLoss) {
-                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Success", (arcaneBypass ? 100 : Repair.getEnchantChance(arcaneForgingRank))));
+                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Success", (arcaneBypass ? 100 : UserManager.getPlayer(player).getRepairManager().getKeepEnchantChance())));
             }
 
             if (Repair.arcaneForgingDowngrades) {
-                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Downgrade", (arcaneBypass ? 0 : Repair.getDowngradeChance(arcaneForgingRank))));
+                player.sendMessage(LocaleLoader.getString("Repair.Arcane.Chance.Downgrade", (arcaneBypass ? 0 : UserManager.getPlayer(player).getRepairManager().getDowngradeEnchantChance())));
             }
         }
     }

+ 5 - 0
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -28,6 +28,7 @@ import com.gmail.nossr50.skills.excavation.ExcavationManager;
 import com.gmail.nossr50.skills.fishing.FishingManager;
 import com.gmail.nossr50.skills.herbalism.HerbalismManager;
 import com.gmail.nossr50.skills.mining.MiningManager;
+import com.gmail.nossr50.skills.repair.RepairManager;
 import com.gmail.nossr50.skills.smelting.SmeltingManager;
 import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
@@ -144,6 +145,10 @@ public class McMMOPlayer {
         return (MiningManager) skillManagers.get(SkillType.MINING);
     }
 
+    public RepairManager getRepairManager() {
+        return (RepairManager) skillManagers.get(SkillType.REPAIR);
+    }
+
     public SmeltingManager getSmeltingManager() {
         return (SmeltingManager) skillManagers.get(SkillType.SMELTING);
     }

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

@@ -35,6 +35,7 @@ import com.gmail.nossr50.skills.excavation.ExcavationManager;
 import com.gmail.nossr50.skills.herbalism.HerbalismManager;
 import com.gmail.nossr50.skills.mining.MiningManager;
 import com.gmail.nossr50.skills.repair.Repair;
+import com.gmail.nossr50.skills.repair.RepairManager;
 import com.gmail.nossr50.skills.repair.Salvage;
 import com.gmail.nossr50.skills.smelting.SmeltingManager;
 import com.gmail.nossr50.skills.unarmed.Unarmed;
@@ -116,10 +117,11 @@ public class BlockListener implements Listener {
         }
 
         if (Repair.anvilMessagesEnabled) {
+            RepairManager repairManager = UserManager.getPlayer(player).getRepairManager();
             int blockID = blockState.getTypeId();
 
             if (blockID == Repair.anvilID) {
-                Repair.placedAnvilCheck(player, blockID);
+                repairManager.placedAnvilCheck(blockID);
             }
             else if (blockID == Salvage.anvilID) {
                 Salvage.placedAnvilCheck(player, blockID);

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

@@ -285,8 +285,8 @@ public class PlayerListener implements Listener {
                 int blockID = block.getTypeId();
 
                 /* REPAIR CHECKS */
-                if (blockID == Repair.anvilID && Permissions.skillEnabled(player, SkillType.REPAIR) && mcMMO.repairManager.isRepairable(heldItem)) {
-                    mcMMO.repairManager.handleRepair(mcMMOPlayer, heldItem);
+                if (blockID == Repair.anvilID && Permissions.skillEnabled(player, SkillType.REPAIR) && mcMMO.repairableManager.isRepairable(heldItem)) {
+                    UserManager.getPlayer(player).getRepairManager().handleRepair(heldItem);
                     event.setCancelled(true);
                     player.updateInventory();
                 }

+ 5 - 5
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -45,8 +45,8 @@ import com.gmail.nossr50.runnables.party.PartyLoaderTask;
 import com.gmail.nossr50.runnables.skills.BleedTimerTask;
 import com.gmail.nossr50.runnables.skills.SkillMonitorTask;
 import com.gmail.nossr50.skills.child.ChildConfig;
-import com.gmail.nossr50.skills.repair.RepairManager;
-import com.gmail.nossr50.skills.repair.RepairManagerFactory;
+import com.gmail.nossr50.skills.repair.RepairableManager;
+import com.gmail.nossr50.skills.repair.RepairableManagerFactory;
 import com.gmail.nossr50.skills.repair.Repairable;
 import com.gmail.nossr50.skills.repair.config.RepairConfigManager;
 import com.gmail.nossr50.util.LogFilter;
@@ -71,7 +71,7 @@ public class mcMMO extends JavaPlugin {
     public static mcMMO p;
 
     public static ChunkManager  placeStore;
-    public static RepairManager repairManager;
+    public static RepairableManager repairableManager;
 
     // Jar Stuff
     public static File mcmmo;
@@ -377,8 +377,8 @@ public class mcMMO extends JavaPlugin {
         // Load repair configs, make manager, and register them at this time
         RepairConfigManager rManager = new RepairConfigManager(this);
         repairables.addAll(rManager.getLoadedRepairables());
-        repairManager = RepairManagerFactory.getRepairManager(repairables.size());
-        repairManager.registerRepairables(repairables);
+        repairableManager = RepairableManagerFactory.getRepairManager(repairables.size());
+        repairableManager.registerRepairables(repairables);
 
         // Check if Repair Anvil and Salvage Anvil have different itemID's
         if (configInstance.getSalvageAnvilId() == configInstance.getRepairAnvilId()) {

+ 66 - 236
src/main/java/com/gmail/nossr50/skills/repair/Repair.java

@@ -1,29 +1,46 @@
 package com.gmail.nossr50.skills.repair;
 
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.bukkit.Material;
-import org.bukkit.Sound;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
-import org.getspout.spoutapi.SpoutManager;
-import org.getspout.spoutapi.player.SpoutPlayer;
+import org.bukkit.inventory.PlayerInventory;
 
-import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
-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.Misc;
-import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.player.UserManager;
-import com.gmail.nossr50.util.skills.PerksUtils;
 
 public class Repair {
+    // The order of the values is extremely important, a few methods depend on it to work properly
+    protected enum Tier {
+        FOUR(4) {
+            @Override public int getLevel() { return AdvancedConfig.getInstance().getArcaneForgingRankLevels4(); }
+            @Override public int getKeepEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank4(); }
+            @Override public int getDowngradeEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank4(); }},
+        THREE(3) {
+            @Override public int getLevel() { return AdvancedConfig.getInstance().getArcaneForgingRankLevels3(); }
+            @Override public int getKeepEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank3(); }
+            @Override public int getDowngradeEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank4(); }},
+        TWO(2) {
+            @Override public int getLevel() { return AdvancedConfig.getInstance().getArcaneForgingRankLevels2(); }
+            @Override public int getKeepEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank2(); }
+            @Override public int getDowngradeEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank4(); }},
+        ONE(1) {
+            @Override public int getLevel() { return AdvancedConfig.getInstance().getArcaneForgingRankLevels1(); }
+            @Override public int getKeepEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank1(); }
+            @Override public int getDowngradeEnchantChance() { return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank4(); }};
+
+        int numerical;
+
+        private Tier(int numerical) {
+            this.numerical = numerical;
+        }
+
+        public int toNumerical() {
+            return numerical;
+        }
+
+        abstract protected int getLevel();
+        abstract protected int getKeepEnchantChance();
+        abstract protected int getDowngradeEnchantChance();
+    }
+
     public static int    repairMasteryMaxBonusLevel = AdvancedConfig.getInstance().getRepairMasteryMaxLevel();
     public static double repairMasteryMaxBonus      = AdvancedConfig.getInstance().getRepairMasteryMaxBonus();
 
@@ -37,244 +54,57 @@ public class Repair {
     public static boolean anvilMessagesEnabled = Config.getInstance().getRepairAnvilMessagesEnabled();
 
     /**
-     * Get current Arcane Forging rank.
-     *
-     * @param profile The PlayerProfile of the player to get the rank for
-     * @return The player's current Arcane Forging rank
-     */
-    public static int getArcaneForgingRank(PlayerProfile profile) {
-        int skillLevel = profile.getSkillLevel(SkillType.REPAIR);
-
-        if (skillLevel >= AdvancedConfig.getInstance().getArcaneForgingRankLevels4()) {
-            return 4;
-        }
-        else if (skillLevel >= AdvancedConfig.getInstance().getArcaneForgingRankLevels3()) {
-            return 3;
-        }
-        else if (skillLevel >= AdvancedConfig.getInstance().getArcaneForgingRankLevels2()) {
-            return 2;
-        }
-        else if (skillLevel >= AdvancedConfig.getInstance().getArcaneForgingRankLevels1()) {
-            return 1;
-        }
-        else {
-            return 0;
-        }
-    }
-
-    /**
-     * Handles removing & downgrading enchants.
-     *
-     * @param player Player repairing the item
-     * @param is Item being repaired
-     */
-    protected static void addEnchants(Player player, ItemStack is) {
-        if (Permissions.arcaneBypass(player)) {
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Perfect"));
-            return;
-        }
-        Map<Enchantment, Integer> enchants = is.getEnchantments();
-
-        if (enchants.size() == 0) {
-            return;
-        }
-
-        int rank = getArcaneForgingRank(UserManager.getPlayer(player).getProfile());
-
-        if (rank == 0 || !Permissions.arcaneForging(player)) {
-            for (Enchantment x : enchants.keySet()) {
-                is.removeEnchantment(x);
-            }
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Lost"));
-            return;
-        }
-
-        boolean downgraded = false;
-
-        for (Entry<Enchantment, Integer> enchant : enchants.entrySet()) {
-            Enchantment enchantment = enchant.getKey();
-
-            int activationChance = PerksUtils.handleLuckyPerks(player, SkillType.REPAIR);
-
-            if (Misc.getRandom().nextInt(activationChance) <= getEnchantChance(rank)) {
-                int enchantLevel = enchant.getValue();
-
-                if (arcaneForgingDowngrades && enchantLevel > 1) {
-                    if (Misc.getRandom().nextInt(activationChance) < getDowngradeChance(rank)) {
-                        is.addEnchantment(enchantment, --enchantLevel);
-                        downgraded = true;
-                    }
-                }
-            }
-            else {
-                is.removeEnchantment(enchantment);
-            }
-        }
-
-        Map<Enchantment, Integer> newEnchants = is.getEnchantments();
-
-        if (newEnchants.isEmpty()) {
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Fail"));
-        }
-        else if (downgraded || newEnchants.size() < enchants.size()) {
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Downgrade"));
-        }
-        else {
-            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Perfect"));
-        }
-    }
-
-    /**
-     * Gets chance of keeping enchantment during repair.
-     *
-     * @param rank Arcane Forging rank
-     * @return The chance of keeping the enchantment
-     */
-    public static int getEnchantChance(int rank) {
-        switch (rank) {
-            case 4:
-                return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank4();
-
-            case 3:
-                return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank3();
-
-            case 2:
-                return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank2();
-
-            case 1:
-                return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChanceRank1();
-
-            default:
-                return 0;
-        }
-    }
-
-    /**
-     * Gets chance of enchantment being downgraded during repair.
-     *
-     * @param rank Arcane Forging rank
-     * @return The chance of the enchantment being downgraded
-     */
-    public static int getDowngradeChance(int rank) {
-        switch (rank) {
-            case 4:
-                return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank4();
-
-            case 3:
-                return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank3();
-
-            case 2:
-                return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank2();
-
-            case 1:
-                return AdvancedConfig.getInstance().getArcaneForgingDowngradeChanceRank1();
-
-            default:
-                return 100;
-        }
-    }
-
-    /**
-     * Checks for Super Repair bonus.
+     * Search the inventory for an item and return the index.
      *
-     * @param player The player repairing an item
-     * @return true if bonus granted, false otherwise
+     * @param inventory PlayerInventory to scan
+     * @param itemId Item id to look for
+     * @return index location where the item was found, or -1 if not found
      */
-    public static boolean checkPlayerProcRepair(Player player) {
-        int skillLevel = UserManager.getPlayer(player).getProfile().getSkillLevel(SkillType.REPAIR);
+    protected static int findInInventory(PlayerInventory inventory, int itemId) {
+        int location = inventory.first(itemId);
 
-        int chance = (int) ((superRepairMaxChance / superRepairMaxBonusLevel) * skillLevel);
-        if (skillLevel >= superRepairMaxBonusLevel) {
-            chance = (int) superRepairMaxChance;
+        // VALIDATE
+        if (inventory.getItem(location).getTypeId() == itemId) {
+            return location;
         }
 
-        int activationChance = PerksUtils.handleLuckyPerks(player, SkillType.REPAIR);
-
-        if (chance > Misc.getRandom().nextInt(activationChance) && Permissions.superRepair(player)) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.FeltEasy"));
-            return true;
-        }
-        return false;
+        return -1;
     }
 
     /**
-     * Handles notifications for placing an anvil.
+     * Search the inventory for an item and return the index.
      *
-     * @param player The player placing the anvil
-     * @param anvilID The item ID of the anvil block
+     * @param inventory PlayerInventory to scan
+     * @param itemId Item id to look for
+     * @param metadata Metadata to look for
+     * @return index location where the item was found, or -1 if not found
      */
-    public static void placedAnvilCheck(Player player, int anvilID) {
-        McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
-
-        if (!mcMMOPlayer.getPlacedAnvil()) {
-            if (mcMMO.spoutEnabled) {
-                SpoutPlayer spoutPlayer = SpoutManager.getPlayer(player);
+    protected static int findInInventory(PlayerInventory inventory, int itemId, byte metadata) {
+        int location = -1;
 
-                if (spoutPlayer.isSpoutCraftEnabled()) {
-                    spoutPlayer.sendNotification(LocaleLoader.getString("Repair.AnvilPlaced.Spout1"), LocaleLoader.getString("Repair.AnvilPlaced.Spout2"), Material.getMaterial(anvilID));
-                }
-            }
-            else {
-                player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
+        for (ItemStack item : inventory.getContents()) {
+            if (item == null) {
+                continue;
             }
 
-            player.playSound(player.getLocation(), Sound.ANVIL_LAND, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
-            mcMMOPlayer.togglePlacedAnvil();
+            if (item.getTypeId() == itemId && item.getData().getData() == metadata) {
+                return location;
+            }
         }
-    }
 
-    /**
-     * Handle the Xp gain for repair events.
-     *
-     * @param mcMMOPlayer Player repairing the item
-     * @param durabilityBefore Durability of the item before repair
-     * @param modify Amount to modify the durability by
-     */
-    protected static void xpHandler(McMMOPlayer mcMMOPlayer, short durabilityBefore, short durabilityAfter, double modify) {
-        short dif = (short) ((durabilityBefore - durabilityAfter) * modify);
-        Player player = mcMMOPlayer.getPlayer();
-
-        player.playSound(player.getLocation(), Sound.ANVIL_USE, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
-        mcMMOPlayer.beginXpGain(SkillType.REPAIR, dif * 10);
+        return location;
     }
 
     /**
-     * Computes repair bonuses.
+     * Decrease the amount of items in this slot by one
      *
-     * @param player The player repairing an item
-     * @param skillLevel the skillLevel of the player in Repair
-     * @param durability The durability of the item being repaired
-     * @param repairAmount The base amount of durability repaired to the item
-     * @return The final amount of durability repaired to the item
+     * @param inventory PlayerInventory to work in
+     * @param index Item index to decrement
      */
-    protected static short repairCalculate(Player player, int skillLevel, short durability, int repairAmount) {
-        float bonus;
-        if (skillLevel >= repairMasteryMaxBonusLevel) {
-            bonus = (float) (repairMasteryMaxBonus / 100F);
-        }
-        else {
-            bonus = (((float) skillLevel) / ((float) repairMasteryMaxBonusLevel)) * (float) ((repairMasteryMaxBonus) / 100F);
-        }
-
-        if (Permissions.repairMastery(player)) {
-            bonus = repairAmount * bonus;
-            repairAmount += (int) bonus;
-        }
-
-        if (checkPlayerProcRepair(player)) {
-            repairAmount = (int) (repairAmount * 2D);
-        }
-
-        if (repairAmount <= 0 || repairAmount > 32767) {
-            repairAmount = 32767;
-        }
-
-        durability -= repairAmount;
-
-        if (durability < 0) {
-            durability = 0;
-        }
+    protected static void removeOneFrom(PlayerInventory inventory, int index) {
+        ItemStack item = inventory.getItem(index).clone();
+        item.setAmount(1);
 
-        return durability;
+        inventory.removeItem(item);
     }
 }

+ 318 - 55
src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java

@@ -1,55 +1,318 @@
-package com.gmail.nossr50.skills.repair;
-
-import java.util.List;
-
-import org.bukkit.inventory.ItemStack;
-
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-
-public interface RepairManager {
-    /**
-     * Register a repairable with the RepairManager
-     *
-     * @param repairable Repairable to register
-     */
-    public void registerRepairable(Repairable repairable);
-
-    /**
-     * Register a list of repairables with the RepairManager
-     *
-     * @param repairables List<Repairable> to register
-     */
-    public void registerRepairables(List<Repairable> repairables);
-
-    /**
-     * Checks if an item is repairable
-     *
-     * @param itemId id to check if repairable
-     * @return true if repairable, false if not
-     */
-    public boolean isRepairable(int itemId);
-
-    /**
-     * Checks if an item is repairable
-     *
-     * @param itemStack Item to check if repairable
-     * @return true if repairable, false if not
-     */
-    public boolean isRepairable(ItemStack itemStack);
-
-    /**
-     * Gets the repairable with this id
-     *
-     * @param id Id of the repairable to look for
-     * @return the repairable, can be null
-     */
-    public Repairable getRepairable(int id);
-
-    /**
-     * Handle the repairing of this object
-     *
-     * @param mcMMOPlayer Player that is repairing an item
-     * @param item ItemStack that is being repaired
-     */
-    public void handleRepair(McMMOPlayer mcMMOPlayer, ItemStack item);
-}
+package com.gmail.nossr50.skills.repair;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+import org.getspout.spoutapi.SpoutManager;
+import org.getspout.spoutapi.player.SpoutPlayer;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.datatypes.skills.SkillType;
+import com.gmail.nossr50.events.skills.repair.McMMOPlayerRepairCheckEvent;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.skills.SkillManager;
+import com.gmail.nossr50.skills.repair.Repair.Tier;
+import com.gmail.nossr50.util.Misc;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.StringUtils;
+import com.gmail.nossr50.util.skills.SkillUtils;
+
+public class RepairManager extends SkillManager {
+    public RepairManager(McMMOPlayer mcMMOPlayer) {
+        super(mcMMOPlayer, SkillType.REPAIR);
+    }
+
+    /**
+     * Handles notifications for placing an anvil.
+     *
+     * @param anvilID The item ID of the anvil block
+     */
+    public void placedAnvilCheck(int anvilID) {
+        Player player = getPlayer();
+
+        if (mcMMOPlayer.getPlacedAnvil()) {
+            return;
+        }
+
+        if (mcMMO.spoutEnabled) {
+            SpoutPlayer spoutPlayer = SpoutManager.getPlayer(player);
+
+            if (spoutPlayer.isSpoutCraftEnabled()) {
+                spoutPlayer.sendNotification(LocaleLoader.getString("Repair.AnvilPlaced.Spout1"), LocaleLoader.getString("Repair.AnvilPlaced.Spout2"), Material.getMaterial(anvilID));
+            }
+        }
+        else {
+            player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
+        }
+
+        player.playSound(player.getLocation(), Sound.ANVIL_LAND, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
+        mcMMOPlayer.togglePlacedAnvil();
+    }
+
+    public void handleRepair(ItemStack item) {
+        Player player = getPlayer();
+        int itemId = item.getTypeId();
+
+        Repairable repairable = mcMMO.repairableManager.getRepairable(itemId);
+
+        // Permissions checks on material and item types
+        if (!repairable.getRepairItemType().getPermissions(player)) {
+            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
+            return;
+        }
+
+        if (!repairable.getRepairMaterialType().getPermissions(player)) {
+            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
+            return;
+        }
+
+        int skillLevel = getSkillLevel();
+        int minimumRepairableLevel = repairable.getMinimumLevel();
+
+        // Level check
+        if (skillLevel < minimumRepairableLevel) {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.Adept", minimumRepairableLevel, StringUtils.getPrettyItemString(itemId)));
+            return;
+        }
+
+        PlayerInventory inventory = player.getInventory();
+
+        int repairMaterialId = repairable.getRepairMaterialId();
+        byte repairMaterialMetadata = repairable.getRepairMaterialMetadata();
+
+        // Check if they have the proper material to repair with
+        if (!inventory.contains(repairMaterialId)) {
+            String message = LocaleLoader.getString("Skills.NeedMore", StringUtils.getPrettyItemString(repairMaterialId));
+
+            if (repairMaterialMetadata != (byte) -1) {
+                // TODO: Do something nicer than append the metadata as a :# ?
+                if (Repair.findInInventory(inventory, repairMaterialId, repairMaterialMetadata) == -1) {
+                    message += ":" + repairMaterialMetadata;
+                }
+            }
+
+            player.sendMessage(message);
+            return;
+        }
+
+        short startDurability = item.getDurability();
+
+        // Do not repair if at full durability
+        if (startDurability <= 0) {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.FullDurability"));
+            return;
+        }
+
+        // Do not repair stacked items
+        if (item.getAmount() != 1) {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.StackedItems"));
+            return;
+        }
+
+        // Clear ability buffs before trying to repair.
+        SkillUtils.removeAbilityBuff(item);
+
+        // Lets get down to business,
+        // To defeat, the huns.
+        int baseRepairAmount = repairable.getBaseRepairDurability(); // Did they send me daughters?
+        short newDurability = repairCalculate(startDurability, baseRepairAmount); // When I asked for sons?
+
+        // We're going to hold onto our repair item location
+        int repairItemLocation;
+        if (repairable.getRepairMaterialMetadata() == (byte) -1) {
+            repairItemLocation = Repair.findInInventory(inventory, repairMaterialId);
+        }
+        else {
+            // Special case for when the repairable has metadata that must be addressed
+            repairItemLocation = Repair.findInInventory(inventory, repairMaterialId, repairMaterialMetadata);
+        }
+
+        // This should never happen, but if it does we need to complain loudly about it.
+        if (repairItemLocation == -1) {
+            player.sendMessage(LocaleLoader.getString("Repair.Error"));
+            return;
+        }
+
+        // Call event
+        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (startDurability - newDurability), inventory.getItem(repairItemLocation), item);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        if (event.isCancelled()) {
+            return;
+        }
+
+        // Handle the enchants
+        if (Repair.arcaneForgingEnchantLoss) {
+            addEnchants(item);
+        }
+
+        // Remove the item
+        Repair.removeOneFrom(inventory, repairItemLocation);
+
+        // Give out XP like candy
+        applyXpGain((int) ((startDurability - newDurability) * repairable.getXpMultiplier()) * 10);
+
+        // BWONG BWONG BWONG
+        player.playSound(player.getLocation(), Sound.ANVIL_USE, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
+
+        // Repair the item!
+        item.setDurability(newDurability);
+    }
+
+    /**
+     * Gets the Arcane Forging rank
+     *
+     * @return the current Arcane Forging rank
+     */
+    public int getArcaneForgingRank() {
+        int skillLevel = getSkillLevel();
+
+        for (Tier tier : Tier.values()) {
+            if (skillLevel >= tier.getLevel()) {
+                return tier.toNumerical();
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Gets chance of keeping enchantment during repair.
+     *
+     * @return The chance of keeping the enchantment
+     */
+    public int getKeepEnchantChance() {
+        int skillLevel = getSkillLevel();
+
+        for (Tier tier : Tier.values()) {
+            if (skillLevel >= tier.getLevel()) {
+                return tier.getKeepEnchantChance();
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * Gets chance of enchantment being downgraded during repair.
+     *
+     * @return The chance of the enchantment being downgraded
+     */
+    public int getDowngradeEnchantChance() {
+        int skillLevel = getSkillLevel();
+
+        for (Tier tier : Tier.values()) {
+            if (skillLevel >= tier.getLevel()) {
+                return tier.getDowngradeEnchantChance();
+            }
+        }
+
+        return 100;
+    }
+
+    /**
+     * Computes repair bonuses.
+     *
+     * @param durability The durability of the item being repaired
+     * @param repairAmount The base amount of durability repaired to the item
+     * @return The final amount of durability repaired to the item
+     */
+    private short repairCalculate(short durability, int repairAmount) {
+        Player player = getPlayer();
+
+        if (Permissions.repairMastery(player)) {
+            double bonus = repairAmount * Math.min((((Repair.repairMasteryMaxBonus / Repair.repairMasteryMaxBonusLevel) * getSkillLevel()) / 100.0D), Repair.repairMasteryMaxBonus / 100.0D);
+            repairAmount += bonus;
+        }
+
+        if (Permissions.superRepair(player) && checkPlayerProcRepair()) {
+            repairAmount *= 2.0D;
+        }
+
+        if (repairAmount <= 0 || repairAmount > Short.MAX_VALUE) {
+            repairAmount = Short.MAX_VALUE;
+        }
+
+        return (short) Math.max(durability - repairAmount, 0);
+    }
+
+    /**
+     * Checks for Super Repair bonus.
+     *
+     * @return true if bonus granted, false otherwise
+     */
+    private boolean checkPlayerProcRepair() {
+        if (SkillUtils.activationSuccessful(getSkillLevel(), getActivationChance(), Repair.superRepairMaxChance, Repair.superRepairMaxBonusLevel)) {
+            getPlayer().sendMessage(LocaleLoader.getString("Repair.Skills.FeltEasy"));
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Handles removing & downgrading enchants.
+     *
+     * @param item Item being repaired
+     */
+    private void addEnchants(ItemStack item) {
+        Player player = getPlayer();
+
+        if (Permissions.arcaneBypass(player)) {
+            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Perfect"));
+            return;
+        }
+
+        Map<Enchantment, Integer> enchants = item.getEnchantments();
+
+        if (enchants.size() == 0) {
+            return;
+        }
+
+        if (getArcaneForgingRank() == 0 || !Permissions.arcaneForging(player)) {
+            for (Enchantment enchant : enchants.keySet()) {
+                item.removeEnchantment(enchant);
+            }
+
+            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Lost"));
+            return;
+        }
+
+        boolean downgraded = false;
+
+        for (Entry<Enchantment, Integer> enchant : enchants.entrySet()) {
+            Enchantment enchantment = enchant.getKey();
+
+            if (getKeepEnchantChance() > Misc.getRandom().nextInt(activationChance)) {
+                int enchantLevel = enchant.getValue();
+
+                if (Repair.arcaneForgingDowngrades && enchantLevel > 1 && getDowngradeEnchantChance() > Misc.getRandom().nextInt(activationChance)) {
+                    item.addEnchantment(enchantment, enchantLevel--);
+                    downgraded = true;
+                }
+            }
+            else {
+                item.removeEnchantment(enchantment);
+            }
+        }
+
+        Map<Enchantment, Integer> newEnchants = item.getEnchantments();
+
+        if (newEnchants.isEmpty()) {
+            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Fail"));
+        }
+        else if (downgraded || newEnchants.size() < enchants.size()) {
+            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Downgrade"));
+        }
+        else {
+            player.sendMessage(LocaleLoader.getString("Repair.Arcane.Perfect"));
+        }
+    }
+}

+ 0 - 13
src/main/java/com/gmail/nossr50/skills/repair/RepairManagerFactory.java

@@ -1,13 +0,0 @@
-package com.gmail.nossr50.skills.repair;
-
-public class RepairManagerFactory {
-    public static RepairManager getRepairManager() {
-        // TODO: Add in loading from config what type of manager we want.
-        return new SimpleRepairManager();
-    }
-
-    public static RepairManager getRepairManager(int repairablesSize) {
-        // TODO: Add in loading from config what type of manager we want.
-        return new SimpleRepairManager(repairablesSize);
-    }
-}

+ 45 - 0
src/main/java/com/gmail/nossr50/skills/repair/RepairableManager.java

@@ -0,0 +1,45 @@
+package com.gmail.nossr50.skills.repair;
+
+import java.util.List;
+
+import org.bukkit.inventory.ItemStack;
+
+public interface RepairableManager {
+    /**
+     * Register a repairable with the RepairManager
+     *
+     * @param repairable Repairable to register
+     */
+    public void registerRepairable(Repairable repairable);
+
+    /**
+     * Register a list of repairables with the RepairManager
+     *
+     * @param repairables List<Repairable> to register
+     */
+    public void registerRepairables(List<Repairable> repairables);
+
+    /**
+     * Checks if an item is repairable
+     *
+     * @param itemId id to check if repairable
+     * @return true if repairable, false if not
+     */
+    public boolean isRepairable(int itemId);
+
+    /**
+     * Checks if an item is repairable
+     *
+     * @param itemStack Item to check if repairable
+     * @return true if repairable, false if not
+     */
+    public boolean isRepairable(ItemStack itemStack);
+
+    /**
+     * Gets the repairable with this id
+     *
+     * @param id Id of the repairable to look for
+     * @return the repairable, can be null
+     */
+    public Repairable getRepairable(int id);
+}

+ 13 - 0
src/main/java/com/gmail/nossr50/skills/repair/RepairableManagerFactory.java

@@ -0,0 +1,13 @@
+package com.gmail.nossr50.skills.repair;
+
+public class RepairableManagerFactory {
+    public static RepairableManager getRepairManager() {
+        // TODO: Add in loading from config what type of manager we want.
+        return new SimpleRepairableManager();
+    }
+
+    public static RepairableManager getRepairManager(int repairablesSize) {
+        // TODO: Add in loading from config what type of manager we want.
+        return new SimpleRepairableManager(repairablesSize);
+    }
+}

+ 0 - 214
src/main/java/com/gmail/nossr50/skills/repair/SimpleRepairManager.java

@@ -1,214 +0,0 @@
-package com.gmail.nossr50.skills.repair;
-
-import java.util.HashMap;
-import java.util.List;
-
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.PlayerInventory;
-
-import com.gmail.nossr50.config.AdvancedConfig;
-import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.SkillType;
-import com.gmail.nossr50.events.skills.repair.McMMOPlayerRepairCheckEvent;
-import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.StringUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
-
-public class SimpleRepairManager implements RepairManager {
-    private HashMap<Integer, Repairable> repairables;
-
-    protected SimpleRepairManager() {
-        this(55);
-    }
-
-    protected SimpleRepairManager(int repairablesSize) {
-        this.repairables = new HashMap<Integer, Repairable>(repairablesSize);
-    }
-
-    @Override
-    public void registerRepairable(Repairable repairable) {
-        Integer itemId = repairable.getItemId();
-        repairables.put(itemId, repairable);
-    }
-
-    @Override
-    public void registerRepairables(List<Repairable> repairables) {
-        for (Repairable repairable : repairables) {
-            registerRepairable(repairable);
-        }
-    }
-
-    @Override
-    public boolean isRepairable(int itemId) {
-        return repairables.containsKey(itemId);
-    }
-
-    @Override
-    public boolean isRepairable(ItemStack itemStack) {
-        return isRepairable(itemStack.getTypeId());
-    }
-
-    @Override
-    public Repairable getRepairable(int id) {
-        return repairables.get(id);
-    }
-
-    @Override
-    public void handleRepair(McMMOPlayer mcMMOPlayer, ItemStack item) {
-        Player player = mcMMOPlayer.getPlayer();
-        Repairable repairable = repairables.get(item.getTypeId());
-
-        // Permissions checks on material and item types
-        if (!repairable.getRepairItemType().getPermissions(player)) {
-            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
-            return;
-        }
-
-        if (!repairable.getRepairMaterialType().getPermissions(player)) {
-            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
-            return;
-        }
-
-        int skillLevel = mcMMOPlayer.getProfile().getSkillLevel(SkillType.REPAIR);
-
-        // Level check
-        if (skillLevel < repairable.getMinimumLevel()) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.Adept", repairable.getMinimumLevel(), StringUtils.getPrettyItemString(item.getTypeId())));
-            return;
-        }
-
-        PlayerInventory inventory = player.getInventory();
-
-        // Check if they have the proper material to repair with
-        if (!inventory.contains(repairable.getRepairMaterialId())) {
-            String message = LocaleLoader.getString("Skills.NeedMore", StringUtils.getPrettyItemString(repairable.getRepairMaterialId()));
-            if (repairable.getRepairMaterialMetadata() != (byte) -1) {
-                // TODO: Do something nicer than append the metadata as a :# ?
-                if (findInInventory(inventory, repairable.getRepairMaterialId(), repairable.getRepairMaterialMetadata()) == -1) {
-                    message += ":" + repairable.getRepairMaterialMetadata();
-                }
-            }
-            player.sendMessage(message);
-            return;
-        }
-
-        short startDurability = item.getDurability();
-
-        // Do not repair if at full durability
-        if (startDurability <= 0) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.FullDurability"));
-            return;
-        }
-
-        // Do not repair stacked items
-        if (item.getAmount() != 1) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.StackedItems"));
-            return;
-        }
-
-        // Clear ability buffs before trying to repair.
-        SkillUtils.removeAbilityBuff(item);
-
-        // Lets get down to business,
-        // To defeat, the huns.
-        int baseRepairAmount = repairable.getBaseRepairDurability(); // Did they send me daughters?
-        short newDurability = Repair.repairCalculate(player, skillLevel, startDurability, baseRepairAmount); // When I asked for sons?
-
-        // We're going to hold onto our repair item location
-        int repairItemLocation;
-        if (repairable.getRepairMaterialMetadata() == (byte) -1) {
-            repairItemLocation = findInInventory(inventory, repairable.getRepairMaterialId());
-        }
-        else {
-            // Special case for when the repairable has metadata that must be addressed
-            repairItemLocation = findInInventory(inventory, repairable.getRepairMaterialId(), repairable.getRepairMaterialMetadata());
-        }
-
-        // This should never happen, but if it does we need to complain loudly about it.
-        if (repairItemLocation == -1) {
-            player.sendMessage(LocaleLoader.getString("Repair.Error"));
-            return;
-        }
-
-        // Call event
-        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (startDurability - newDurability), inventory.getItem(repairItemLocation), item);
-        Bukkit.getServer().getPluginManager().callEvent(event);
-
-        if (event.isCancelled()) {
-            return;
-        }
-
-        // Handle the enchants
-        if (AdvancedConfig.getInstance().getArcaneForgingEnchantLossEnabled() && !Permissions.arcaneBypass(player)) {
-            // Generalize away enchantment work
-            Repair.addEnchants(player, item);
-        }
-
-        // Remove the item
-        removeOneFrom(inventory, repairItemLocation);
-
-        // Give out XP like candy
-        Repair.xpHandler(mcMMOPlayer, startDurability, newDurability, repairable.getXpMultiplier());
-
-        // Repair the item!
-        item.setDurability(newDurability);
-    }
-
-    /**
-     * Decrease the amount of items in this slot by one
-     *
-     * @param inventory PlayerInventory to work in
-     * @param index Item index to decrement
-     */
-    private void removeOneFrom(PlayerInventory inventory, int index) {
-        ItemStack item = inventory.getItem(index).clone();
-        item.setAmount(1);
-
-        inventory.removeItem(item);
-    }
-
-    /**
-     * Search the inventory for an item and return the index.
-     *
-     * @param inventory PlayerInventory to scan
-     * @param itemId Item id to look for
-     * @return index location where the item was found, or -1 if not found
-     */
-    private int findInInventory(PlayerInventory inventory, int itemId) {
-        int location = inventory.first(itemId);
-
-        // VALIDATE
-        if (inventory.getItem(location).getTypeId() == itemId) {
-            return location;
-        }
-
-        return -1;
-    }
-
-    /**
-     * Search the inventory for an item and return the index.
-     *
-     * @param inventory PlayerInventory to scan
-     * @param itemId Item id to look for
-     * @param metadata Metadata to look for
-     * @return index location where the item was found, or -1 if not found
-     */
-    private int findInInventory(PlayerInventory inventory, int itemId, byte metadata) {
-        int location = -1;
-
-        for (ItemStack item : inventory.getContents()) {
-            if (item == null) {
-                continue;
-            }
-
-            if (item.getTypeId() == itemId && item.getData().getData() == metadata) {
-                return location;
-            }
-        }
-
-        return location;
-    }
-}

+ 46 - 0
src/main/java/com/gmail/nossr50/skills/repair/SimpleRepairableManager.java

@@ -0,0 +1,46 @@
+package com.gmail.nossr50.skills.repair;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.bukkit.inventory.ItemStack;
+
+public class SimpleRepairableManager implements RepairableManager {
+    private HashMap<Integer, Repairable> repairables;
+
+    protected SimpleRepairableManager() {
+        this(55);
+    }
+
+    protected SimpleRepairableManager(int repairablesSize) {
+        this.repairables = new HashMap<Integer, Repairable>(repairablesSize);
+    }
+
+    @Override
+    public void registerRepairable(Repairable repairable) {
+        Integer itemId = repairable.getItemId();
+        repairables.put(itemId, repairable);
+    }
+
+    @Override
+    public void registerRepairables(List<Repairable> repairables) {
+        for (Repairable repairable : repairables) {
+            registerRepairable(repairable);
+        }
+    }
+
+    @Override
+    public boolean isRepairable(int itemId) {
+        return repairables.containsKey(itemId);
+    }
+
+    @Override
+    public boolean isRepairable(ItemStack itemStack) {
+        return isRepairable(itemStack.getTypeId());
+    }
+
+    @Override
+    public Repairable getRepairable(int id) {
+        return repairables.get(id);
+    }
+}