Browse Source

Most of handleRepair() done, level checking still needed
- Move Repair
- Change visibility of a few methods for repurposing Repair soon

NuclearW 13 years ago
parent
commit
b7cec8a0c4

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

@@ -12,7 +12,7 @@ import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
 import com.gmail.nossr50.datatypes.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.skills.misc.Repair;
+import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.util.Page;
 import com.gmail.nossr50.util.Page;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Users;
 import com.gmail.nossr50.util.Users;

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

@@ -12,7 +12,7 @@ import com.gmail.nossr50.skills.gathering.Excavation;
 import com.gmail.nossr50.skills.gathering.Herbalism;
 import com.gmail.nossr50.skills.gathering.Herbalism;
 import com.gmail.nossr50.skills.gathering.Mining;
 import com.gmail.nossr50.skills.gathering.Mining;
 import com.gmail.nossr50.skills.gathering.WoodCutting;
 import com.gmail.nossr50.skills.gathering.WoodCutting;
-import com.gmail.nossr50.skills.misc.Repair;
+import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.spout.SpoutSounds;
 import com.gmail.nossr50.spout.SpoutSounds;
 import com.gmail.nossr50.util.BlockChecks;
 import com.gmail.nossr50.util.BlockChecks;
 import com.gmail.nossr50.util.ItemChecks;
 import com.gmail.nossr50.util.ItemChecks;

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

@@ -41,7 +41,7 @@ import com.gmail.nossr50.skills.combat.Taming;
 import com.gmail.nossr50.skills.gathering.BlastMining;
 import com.gmail.nossr50.skills.gathering.BlastMining;
 import com.gmail.nossr50.skills.gathering.Fishing;
 import com.gmail.nossr50.skills.gathering.Fishing;
 import com.gmail.nossr50.skills.gathering.Herbalism;
 import com.gmail.nossr50.skills.gathering.Herbalism;
-import com.gmail.nossr50.skills.misc.Repair;
+import com.gmail.nossr50.skills.repair.Repair;
 import com.gmail.nossr50.util.BlockChecks;
 import com.gmail.nossr50.util.BlockChecks;
 import com.gmail.nossr50.util.Item;
 import com.gmail.nossr50.util.Item;
 import com.gmail.nossr50.util.ItemChecks;
 import com.gmail.nossr50.util.ItemChecks;

+ 600 - 587
src/main/java/com/gmail/nossr50/skills/misc/Repair.java → src/main/java/com/gmail/nossr50/skills/repair/Repair.java

@@ -1,587 +1,600 @@
-package com.gmail.nossr50.skills.misc;
-
-import java.util.Map;
-import java.util.Random;
-import java.util.Map.Entry;
-
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
-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.config.Config;
-import com.gmail.nossr50.spout.SpoutSounds;
-import com.gmail.nossr50.util.ItemChecks;
-import com.gmail.nossr50.util.Misc;
-import com.gmail.nossr50.util.ModChecks;
-import com.gmail.nossr50.util.Permissions;
-import com.gmail.nossr50.util.Skills;
-import com.gmail.nossr50.util.Users;
-import com.gmail.nossr50.datatypes.PlayerProfile;
-import com.gmail.nossr50.datatypes.SkillType;
-import com.gmail.nossr50.datatypes.mods.CustomItem;
-import com.gmail.nossr50.datatypes.mods.CustomTool;
-import com.gmail.nossr50.events.skills.McMMOPlayerRepairCheckEvent;
-import com.gmail.nossr50.locale.LocaleLoader;
-
-public class Repair {
-
-    private static Random random = new Random();
-    private static Config configInstance = Config.getInstance();
-    private static Permissions permInstance = Permissions.getInstance();
-
-    /**
-     * Handle all the item repair checks.
-     *
-     * @param player Player repairing the item
-     * @param is The item being repaired
-     */
-    public static void repairCheck(Player player, ItemStack is) {
-        PlayerProfile PP = Users.getProfile(player);
-        short durabilityBefore = is.getDurability();
-        PlayerInventory inventory = player.getInventory();
-        int skillLevel = PP.getSkillLevel(SkillType.REPAIR);
-
-        if (durabilityBefore > 0 && is.getAmount() == 1) {
-
-            /*
-             * REPAIR ARMOR
-             */
-            if (ItemChecks.isArmor(is) && permInstance.armorRepair(player)) {
-                if (ItemChecks.isDiamondArmor(is) && inventory.contains(configInstance.getRepairDiamondMaterial()) && skillLevel >= configInstance.getRepairDiamondLevelRequirement() && permInstance.diamondRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairDiamondMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 6);
-                }
-                else if (ItemChecks.isIronArmor(is) && inventory.contains(configInstance.getRepairIronMaterial()) && skillLevel >= configInstance.getRepairIronLevelRequirement() && permInstance.ironRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairIronMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 2);
-                }
-                else if (ItemChecks.isGoldArmor(is) && inventory.contains(configInstance.getRepairGoldMaterial()) && skillLevel >= configInstance.getRepairGoldLevelRequirement() && permInstance.goldRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairGoldMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 4);
-                }
-                else if (ItemChecks.isLeatherArmor(is) && inventory.contains(configInstance.getRepairLeatherMaterial()) && permInstance.leatherRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairLeatherMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 1);
-                }
-                else {
-                    needMoreVespeneGas(is, player); //UNABLE TO REPAIR
-                }
-            }
-
-            /*
-             * REPAIR TOOLS
-             */
-            else if (ItemChecks.isTool(is) && permInstance.toolRepair(player)) {
-                if (ItemChecks.isStoneTool(is) && inventory.contains(configInstance.getRepairStoneMaterial()) && skillLevel >= configInstance.getRepairStoneLevelRequirement() && permInstance.stoneRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairStoneMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, .5);
-                }
-                else if (ItemChecks.isWoodTool(is) && inventory.contains(configInstance.getRepairWoodMaterial()) && permInstance.woodRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairWoodMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, .5);
-                }
-                else if (ItemChecks.isIronTool(is) && inventory.contains(configInstance.getRepairIronMaterial()) && skillLevel >= configInstance.getRepairIronLevelRequirement() && permInstance.ironRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairIronMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 1);
-                }
-                else if (ItemChecks.isDiamondTool(is) && inventory.contains(configInstance.getRepairDiamondMaterial()) && skillLevel >= configInstance.getRepairDiamondLevelRequirement() && permInstance.diamondRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairDiamondMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 1);
-                }
-                else if (ItemChecks.isGoldTool(is) && inventory.contains(configInstance.getRepairGoldMaterial()) && skillLevel >= configInstance.getRepairGoldLevelRequirement() && permInstance.goldRepair(player)) {
-                    repairItem(player, is, new ItemStack(configInstance.getRepairGoldMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, 8);
-                }
-                else if (ItemChecks.isStringTool(is) && inventory.contains(configInstance.getRepairStringMaterial()) && permInstance.stringRepair(player)){
-                    repairItem(player, is, new ItemStack(configInstance.getRepairStringMaterial()));
-                    xpHandler(player, PP, is, durabilityBefore, .5);
-                }
-                else {
-                    needMoreVespeneGas(is, player); //UNABLE TO REPAIR
-                }
-            }
-
-            /*
-             * REPAIR CUSTOM TOOLS
-             */
-            else if (ModChecks.isCustomTool(is) && permInstance.toolRepair(player)) {
-                ItemStack repairMaterial = ModChecks.getToolFromItemStack(is).getRepairMaterial();
-
-                if (inventory.contains(repairMaterial)) {
-                    repairCustomItem(player, is, repairMaterial);
-                    xpHandler(player, PP, is, durabilityBefore, 1);
-                }
-                else {
-                    needMoreVespeneGas(is, player);
-                }
-            }
-
-            /*
-             * REPAIR CUSTOM ARMOR
-             */
-            else if (ModChecks.isCustomArmor(is) && permInstance.armorRepair(player)) {
-                ItemStack repairMaterial = ModChecks.getArmorFromItemStack(is).getRepairMaterial();
-
-                if (inventory.contains(repairMaterial)) {
-                    repairCustomItem(player, is, repairMaterial);
-                    xpHandler(player, PP, is, durabilityBefore, 1);
-                }
-                else {
-                    needMoreVespeneGas(is, player);
-                }
-            }
-        }
-        else {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.FullDurability"));
-        }
-    }
-
-    /**
-     * Handle the XP gain for repair events.
-     *
-     * @param player Player repairing the item
-     * @param PP PlayerProfile of the repairing player
-     * @param is Item being repaired
-     * @param durabilityBefore Durability of the item before repair
-     * @param modify Amount to modify the durability by
-     * @param boost True if the modifier is a boost, false if the modifier is a reduction
-     */
-    private static void xpHandler(Player player, PlayerProfile PP, ItemStack is, short durabilityBefore, double modify) {
-        short durabilityAfter = is.getDurability();
-        short dif = (short) (durabilityBefore - durabilityAfter);
-
-        dif = (short) (dif * modify);
-
-        //TODO: What exactly is this for, and should we have it for armor as well?
-        if (ItemChecks.isShovel(is)) {
-            dif = (short) (dif / 3);
-        }
-        else if(ItemChecks.isSword(is)) {
-            dif = (short) (dif / 2);
-        }
-        else if(ItemChecks.isHoe(is)) {
-            dif = (short) (dif / 2);
-        }
-
-        PP.addXP(player, SkillType.REPAIR, dif * 10);
-        Skills.XpCheckSkill(SkillType.REPAIR, player);
-
-        //CLANG CLANG
-        if (configInstance.spoutEnabled) {
-            SpoutSounds.playRepairNoise(player, mcMMO.p);
-        }
-    }
-
-    /**
-     * Get current Arcane Forging rank.
-     * 
-     * @param skillLevel The skill level of the player whose rank is being checked
-     * @return The player's current Arcane Forging rank
-     */
-    public static int getArcaneForgingRank(PlayerProfile PP) {
-        int skillLevel = PP.getSkillLevel(SkillType.REPAIR);
-
-        if (skillLevel >= configInstance.getArcaneForgingRankLevels4()) {
-            return 4;
-        }
-        else if (skillLevel >= configInstance.getArcaneForgingRankLevels3()) {
-            return 3;
-        }
-        else if (skillLevel >= configInstance.getArcaneForgingRankLevels2()) {
-            return 2;
-        }
-        else if (skillLevel >= configInstance.getArcaneForgingRankLevels1()) {
-            return 1;
-        }
-        else {
-            return 0;
-        }
-    }
-
-    /**
-     * Handles removing & downgrading enchants.
-     *
-     * @param player Player repairing the item
-     * @param is Item being repaired
-     */
-    private static void addEnchants(Player player, ItemStack is) {
-        Map<Enchantment, Integer> enchants = is.getEnchantments();
-
-        if (enchants.size() == 0) {
-            return;
-        }
-
-        int rank = getArcaneForgingRank(Users.getProfile(player));
-
-        if (rank == 0 || !permInstance.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();
-
-            if (random.nextInt(100) <= getEnchantChance(rank)) {
-                int enchantLevel = enchant.getValue();
-
-                if (configInstance.getArcaneForgingDowngradeEnabled() && enchantLevel > 1) {
-                    if (random.nextInt(100) <= 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 configInstance.getArcaneForgingKeepEnchantsChanceRank4();
-
-        case 3:
-            return configInstance.getArcaneForgingKeepEnchantsChanceRank3();
-
-        case 2:
-            return configInstance.getArcaneForgingKeepEnchantsChanceRank2();
-
-        case 1:
-            return configInstance.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 configInstance.getArcaneForgingDowngradeChanceRank4();
-
-        case 3:
-            return configInstance.getArcaneForgingDowngradeChanceRank3();
-
-        case 2:
-            return configInstance.getArcaneForgingDowngradeChanceRank2();
-
-        case 1:
-            return configInstance.getArcaneForgingDowngradeChanceRank1();
-
-        default:
-            return 100;
-        }
-    }
-
-    /**
-     * Computes repair bonuses.
-     *
-     * @param player The player repairing an item
-     * @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 static short repairCalculate(Player player, short durability, int repairAmount) {
-        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
-        float bonus = (float) skillLevel / 500;
-
-        if (permInstance.repairMastery(player)) {
-            bonus = (repairAmount * bonus);
-            repairAmount += bonus;
-        }
-
-        if (checkPlayerProcRepair(player)) {
-            repairAmount = (short) (repairAmount * 2);
-        }
-
-        durability -= repairAmount;
-
-        if (durability < 0) {
-            durability = 0;
-        }
-
-        return durability;
-    }
-
-    /**
-     * Gets the base durability amount to repair an item.
-     *
-     * @param is The item being repaired
-     * @param player The player repairing the item
-     * @return The final amount of durability repaired to the item
-     */
-    private static short getRepairAmount(ItemStack is, Player player){
-        short maxDurability = is.getType().getMaxDurability();
-        int repairAmount = 0;
-
-        if (ItemChecks.isShovel(is)) {
-            repairAmount = maxDurability;
-        }
-        else if (ItemChecks.isHoe(is) || ItemChecks.isSword(is) || is.getType().equals(Material.SHEARS) || is.getType().equals(Material.FISHING_ROD)) {
-            repairAmount = maxDurability / 2;
-        }
-        else if (ItemChecks.isAxe(is) || ItemChecks.isPickaxe(is) || is.getType().equals(Material.BOW)) {
-            repairAmount = maxDurability / 3;
-        }
-        else if (ItemChecks.isBoots(is)) {
-            repairAmount = maxDurability / 4;
-        }
-        else if (ItemChecks.isHelmet(is)) {
-            repairAmount = maxDurability / 5;
-        }
-        else if (ItemChecks.isPants(is)) {
-            repairAmount = maxDurability / 7;
-        }
-        else if (ItemChecks.isChestplate(is)) {
-            repairAmount = maxDurability / 8;
-        }
-
-        return repairCalculate(player, is.getDurability(), repairAmount);
-    }
-
-    /**
-     * Gets the base durability amount to repair a custom item.
-     *
-     * @param is The custom item being repaired
-     * @param player The player repairing the custom item
-     * @return The final amount of durability repaired to the custom item
-     */
-    private static short getCustomRepairAmount(ItemStack is, Player player) {
-        short maxDurability = 0;
-        int materialsRequired = 0;
-        int repairAmount = 0;
-
-        CustomTool tool = ModChecks.getToolFromItemStack(is);
-        CustomItem armor = ModChecks.getArmorFromItemStack(is);
-
-        if (tool != null) {
-            maxDurability = tool.getDurability();
-            materialsRequired = tool.getRepairQuantity();
-        }
-        else if (armor != null) {
-            maxDurability = armor.getDurability();
-            materialsRequired = armor.getRepairQuantity();
-        }
-
-        repairAmount = maxDurability / materialsRequired;
-
-        return repairCalculate(player, is.getDurability(), repairAmount);
-    }
-
-    /**
-     * Informs a player that the repair has failed.
-     *
-     * @param is The item being repaired
-     * @param player The player repairing the item
-     */
-    private static void needMoreVespeneGas(ItemStack is, Player player) {
-        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
-
-        if (is.getAmount() != 1) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.StackedItems"));
-        }
-        else {
-            if (ItemChecks.isDiamondTool(is) || ItemChecks.isDiamondArmor(is)) {
-                if (skillLevel < configInstance.getRepairDiamondLevelRequirement()) {
-                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptDiamond"));
-                }
-                else {
-                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.BLUE + Misc.prettyItemString(configInstance.getRepairDiamondMaterial()));
-                }
-            }
-            else if (ItemChecks.isIronTool(is) || ItemChecks.isIronArmor(is)) {
-                if (skillLevel < configInstance.getRepairIronLevelRequirement()) {
-                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptIron"));
-                }
-                else {
-                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore")+ " " + ChatColor.GRAY + Misc.prettyItemString(configInstance.getRepairIronMaterial()));
-                }
-            }
-            else if (ItemChecks.isGoldTool(is) || ItemChecks.isGoldArmor(is)) {
-                if (skillLevel < configInstance.getRepairGoldLevelRequirement()) {
-                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptGold"));
-                }
-                else {
-                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.GOLD + Misc.prettyItemString(configInstance.getRepairGoldMaterial()));
-                }
-            }
-            else if (ItemChecks.isStoneTool(is)) {
-                if (skillLevel < configInstance.getRepairStoneLevelRequirement()) {
-                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptStone"));
-                }
-                else {
-                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.GRAY + Misc.prettyItemString(configInstance.getRepairStoneMaterial()));
-                }
-            }
-            else if (ItemChecks.isWoodTool(is)) {
-                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.DARK_GREEN + Misc.prettyItemString(configInstance.getRepairWoodMaterial()));
-            }
-            else if (ItemChecks.isLeatherArmor(is)) {
-                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.YELLOW + Misc.prettyItemString(configInstance.getRepairLeatherMaterial()));
-            }
-            else if (ItemChecks.isStringTool(is)) {
-                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.YELLOW + Misc.prettyItemString(configInstance.getRepairStringMaterial()));
-            }
-            else {
-                player.sendMessage("You do not have the material needed to repair this item!"); //TODO: Use locale
-            }
-        }
-    }
-
-    /**
-     * Checks for Super Repair bonus.
-     *
-     * @param player The player repairing an item
-     * @return true if bonus granted, false otherwise
-     */
-    public static boolean checkPlayerProcRepair(Player player) {
-        final int MAX_BONUS_LEVEL = 1000;
-
-        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
-
-        if ((skillLevel > MAX_BONUS_LEVEL || random.nextInt(1000) <= skillLevel) && permInstance.repairBonus(player)) {
-            player.sendMessage(LocaleLoader.getString("Repair.Skills.FeltEasy"));
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Repairs an item.
-     *
-     * @param player The player repairing an item
-     * @param item The item being repaired
-     * @param repairMaterial The repair reagent
-     */
-    private static void repairItem(Player player, ItemStack item, ItemStack repairMaterial) {
-        short initialDurability = item.getDurability();
-        short newDurability = getRepairAmount(item, player);
-        PlayerInventory inventory = player.getInventory();
-
-        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (initialDurability - newDurability), repairMaterial, item);
-        mcMMO.p.getServer().getPluginManager().callEvent(event);
-
-        if (event.isCancelled()) {
-            return;
-        }
-
-        if (repairMaterial.getType().equals(Material.WOOD)) {
-            removeWood(inventory);
-        }
-        else {
-            inventory.removeItem(repairMaterial);
-        }
-
-        /* Handle the enchants */
-        if (configInstance.getArcaneForgingEnchantLossEnabled() && !permInstance.arcaneBypass(player)) {
-            addEnchants(player, item);
-        }
-
-        item.setDurability(newDurability);
-    }
-
-    /**
-     * Repairs a custom item.
-     *
-     * @param player The player repairing an item
-     * @param item The custom item being repaired
-     * @param repairMaterial The repair reagent
-     */
-    private static void repairCustomItem(Player player, ItemStack item, ItemStack repairMaterial) {
-        short initialDurability = item.getDurability();
-        short newDurability = getCustomRepairAmount(item, player);
-        PlayerInventory inventory = player.getInventory();
-
-        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (initialDurability - newDurability), repairMaterial, item);
-        mcMMO.p.getServer().getPluginManager().callEvent(event);
-
-        if (event.isCancelled()) {
-            return;
-        }
-
-        inventory.removeItem(repairMaterial);
-
-        if (configInstance.getArcaneForgingEnchantLossEnabled() && !permInstance.arcaneBypass(player)) {
-            addEnchants(player, item);
-        }
-
-        item.setDurability(newDurability);
-    }
-
-    /**
-     * Handles notifications for placing an anvil.
-     *
-     * @param player The player placing the anvil
-     * @param anvilID The item ID of the anvil block
-     */
-    public static void placedAnvilCheck(Player player, int anvilID) {
-        PlayerProfile PP = Users.getProfile(player);
-
-        if (!PP.getPlacedAnvil()) {
-            if (configInstance.spoutEnabled) {
-                SpoutPlayer sPlayer = SpoutManager.getPlayer(player);
-
-                if (sPlayer.isSpoutCraftEnabled()) {
-                    sPlayer.sendNotification("[mcMMO] Anvil Placed", "Right click to repair!", Material.getMaterial(anvilID)); //TODO: Use Locale
-                }
-            }
-            else {
-                player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
-            }
-
-            PP.togglePlacedAnvil();
-        }
-    }
-
-    /**
-     * Removes wood from a player's inventory on repair. Needed due to wood having multiple possible data values.
-     *
-     * @param inventory The inventory to remove wood from
-     */
-    private static void removeWood(PlayerInventory inventory) {
-        //TODO: Make this less hackish once there's a better way to do it...
-        int slot = inventory.first(Material.WOOD);
-        ItemStack item = inventory.getItem(slot);
-        item.setAmount(item.getAmount() - 1);
-        inventory.setItem(slot, item);
-    }
-}
+package com.gmail.nossr50.skills.repair;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.Map.Entry;
+
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+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.config.Config;
+import com.gmail.nossr50.spout.SpoutSounds;
+import com.gmail.nossr50.util.ItemChecks;
+import com.gmail.nossr50.util.Misc;
+import com.gmail.nossr50.util.ModChecks;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.Skills;
+import com.gmail.nossr50.util.Users;
+import com.gmail.nossr50.datatypes.PlayerProfile;
+import com.gmail.nossr50.datatypes.SkillType;
+import com.gmail.nossr50.datatypes.mods.CustomItem;
+import com.gmail.nossr50.datatypes.mods.CustomTool;
+import com.gmail.nossr50.events.skills.McMMOPlayerRepairCheckEvent;
+import com.gmail.nossr50.locale.LocaleLoader;
+
+public class Repair {
+
+    private static Random random = new Random();
+    private static Config configInstance = Config.getInstance();
+    private static Permissions permInstance = Permissions.getInstance();
+
+    /**
+     * Handle all the item repair checks.
+     *
+     * @param player Player repairing the item
+     * @param is The item being repaired
+     */
+    public static void repairCheck(Player player, ItemStack is) {
+        PlayerProfile PP = Users.getProfile(player);
+        short durabilityBefore = is.getDurability();
+        PlayerInventory inventory = player.getInventory();
+        int skillLevel = PP.getSkillLevel(SkillType.REPAIR);
+
+        if (durabilityBefore > 0 && is.getAmount() == 1) {
+
+            /*
+             * REPAIR ARMOR
+             */
+            if (ItemChecks.isArmor(is) && permInstance.armorRepair(player)) {
+                if (ItemChecks.isDiamondArmor(is) && inventory.contains(configInstance.getRepairDiamondMaterial()) && skillLevel >= configInstance.getRepairDiamondLevelRequirement() && permInstance.diamondRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairDiamondMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 6);
+                }
+                else if (ItemChecks.isIronArmor(is) && inventory.contains(configInstance.getRepairIronMaterial()) && skillLevel >= configInstance.getRepairIronLevelRequirement() && permInstance.ironRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairIronMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 2);
+                }
+                else if (ItemChecks.isGoldArmor(is) && inventory.contains(configInstance.getRepairGoldMaterial()) && skillLevel >= configInstance.getRepairGoldLevelRequirement() && permInstance.goldRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairGoldMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 4);
+                }
+                else if (ItemChecks.isLeatherArmor(is) && inventory.contains(configInstance.getRepairLeatherMaterial()) && permInstance.leatherRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairLeatherMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 1);
+                }
+                else {
+                    needMoreVespeneGas(is, player); //UNABLE TO REPAIR
+                }
+            }
+
+            /*
+             * REPAIR TOOLS
+             */
+            else if (ItemChecks.isTool(is) && permInstance.toolRepair(player)) {
+                if (ItemChecks.isStoneTool(is) && inventory.contains(configInstance.getRepairStoneMaterial()) && skillLevel >= configInstance.getRepairStoneLevelRequirement() && permInstance.stoneRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairStoneMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, .5);
+                }
+                else if (ItemChecks.isWoodTool(is) && inventory.contains(configInstance.getRepairWoodMaterial()) && permInstance.woodRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairWoodMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, .5);
+                }
+                else if (ItemChecks.isIronTool(is) && inventory.contains(configInstance.getRepairIronMaterial()) && skillLevel >= configInstance.getRepairIronLevelRequirement() && permInstance.ironRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairIronMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 1);
+                }
+                else if (ItemChecks.isDiamondTool(is) && inventory.contains(configInstance.getRepairDiamondMaterial()) && skillLevel >= configInstance.getRepairDiamondLevelRequirement() && permInstance.diamondRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairDiamondMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 1);
+                }
+                else if (ItemChecks.isGoldTool(is) && inventory.contains(configInstance.getRepairGoldMaterial()) && skillLevel >= configInstance.getRepairGoldLevelRequirement() && permInstance.goldRepair(player)) {
+                    repairItem(player, is, new ItemStack(configInstance.getRepairGoldMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, 8);
+                }
+                else if (ItemChecks.isStringTool(is) && inventory.contains(configInstance.getRepairStringMaterial()) && permInstance.stringRepair(player)){
+                    repairItem(player, is, new ItemStack(configInstance.getRepairStringMaterial()));
+                    xpHandler(player, PP, is, durabilityBefore, .5);
+                }
+                else {
+                    needMoreVespeneGas(is, player); //UNABLE TO REPAIR
+                }
+            }
+
+            /*
+             * REPAIR CUSTOM TOOLS
+             */
+            else if (ModChecks.isCustomTool(is) && permInstance.toolRepair(player)) {
+                ItemStack repairMaterial = ModChecks.getToolFromItemStack(is).getRepairMaterial();
+
+                if (inventory.contains(repairMaterial)) {
+                    repairCustomItem(player, is, repairMaterial);
+                    xpHandler(player, PP, is, durabilityBefore, 1);
+                }
+                else {
+                    needMoreVespeneGas(is, player);
+                }
+            }
+
+            /*
+             * REPAIR CUSTOM ARMOR
+             */
+            else if (ModChecks.isCustomArmor(is) && permInstance.armorRepair(player)) {
+                ItemStack repairMaterial = ModChecks.getArmorFromItemStack(is).getRepairMaterial();
+
+                if (inventory.contains(repairMaterial)) {
+                    repairCustomItem(player, is, repairMaterial);
+                    xpHandler(player, PP, is, durabilityBefore, 1);
+                }
+                else {
+                    needMoreVespeneGas(is, player);
+                }
+            }
+        }
+        else {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.FullDurability"));
+        }
+    }
+
+    /**
+     * Handle the XP gain for repair events.
+     *
+     * @param player Player repairing the item
+     * @param PP PlayerProfile of the repairing player
+     * @param is Item being repaired
+     * @param durabilityBefore Durability of the item before repair
+     * @param modify Amount to modify the durability by
+     * @param boost True if the modifier is a boost, false if the modifier is a reduction
+     */
+    private static void xpHandler(Player player, PlayerProfile PP, ItemStack is, short durabilityBefore, double modify) {
+        short durabilityAfter = is.getDurability();
+        short dif = (short) (durabilityBefore - durabilityAfter);
+
+        dif = (short) (dif * modify);
+
+        //TODO: What exactly is this for, and should we have it for armor as well?
+        if (ItemChecks.isShovel(is)) {
+            dif = (short) (dif / 3);
+        }
+        else if(ItemChecks.isSword(is)) {
+            dif = (short) (dif / 2);
+        }
+        else if(ItemChecks.isHoe(is)) {
+            dif = (short) (dif / 2);
+        }
+
+        PP.addXP(player, SkillType.REPAIR, dif * 10);
+        Skills.XpCheckSkill(SkillType.REPAIR, player);
+
+        //CLANG CLANG
+        if (configInstance.spoutEnabled) {
+            SpoutSounds.playRepairNoise(player, mcMMO.p);
+        }
+    }
+
+    /**
+     * Get current Arcane Forging rank.
+     *
+     * @param skillLevel The skill level of the player whose rank is being checked
+     * @return The player's current Arcane Forging rank
+     */
+    public static int getArcaneForgingRank(PlayerProfile PP) {
+        int skillLevel = PP.getSkillLevel(SkillType.REPAIR);
+
+        if (skillLevel >= configInstance.getArcaneForgingRankLevels4()) {
+            return 4;
+        }
+        else if (skillLevel >= configInstance.getArcaneForgingRankLevels3()) {
+            return 3;
+        }
+        else if (skillLevel >= configInstance.getArcaneForgingRankLevels2()) {
+            return 2;
+        }
+        else if (skillLevel >= configInstance.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) {
+        Map<Enchantment, Integer> enchants = is.getEnchantments();
+
+        if (enchants.size() == 0) {
+            return;
+        }
+
+        int rank = getArcaneForgingRank(Users.getProfile(player));
+
+        if (rank == 0 || !permInstance.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();
+
+            if (random.nextInt(100) <= getEnchantChance(rank)) {
+                int enchantLevel = enchant.getValue();
+
+                if (configInstance.getArcaneForgingDowngradeEnabled() && enchantLevel > 1) {
+                    if (random.nextInt(100) <= 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 configInstance.getArcaneForgingKeepEnchantsChanceRank4();
+
+        case 3:
+            return configInstance.getArcaneForgingKeepEnchantsChanceRank3();
+
+        case 2:
+            return configInstance.getArcaneForgingKeepEnchantsChanceRank2();
+
+        case 1:
+            return configInstance.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 configInstance.getArcaneForgingDowngradeChanceRank4();
+
+        case 3:
+            return configInstance.getArcaneForgingDowngradeChanceRank3();
+
+        case 2:
+            return configInstance.getArcaneForgingDowngradeChanceRank2();
+
+        case 1:
+            return configInstance.getArcaneForgingDowngradeChanceRank1();
+
+        default:
+            return 100;
+        }
+    }
+
+    /**
+     * Computes repair bonuses.
+     *
+     * @param player The player repairing an item
+     * @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 static short repairCalculate(Player player, short durability, int repairAmount) {
+        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
+        return repairCalculate(player, skillLevel, durability, repairAmount);
+    }
+
+    /**
+     * Computes repair bonuses.
+     *
+     * @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
+     */
+    protected static short repairCalculate(Player player, int skillLevel, short durability, int repairAmount) {
+        float bonus = (float) skillLevel / 500;
+
+        if (permInstance.repairMastery(player)) {
+            bonus = (repairAmount * bonus);
+            repairAmount += bonus;
+        }
+
+        if (checkPlayerProcRepair(player)) {
+            repairAmount = (short) (repairAmount * 2);
+        }
+
+        durability -= repairAmount;
+
+        if (durability < 0) {
+            durability = 0;
+        }
+
+        return durability;
+    }
+
+    /**
+     * Gets the base durability amount to repair an item.
+     *
+     * @param is The item being repaired
+     * @param player The player repairing the item
+     * @return The final amount of durability repaired to the item
+     */
+    private static short getRepairAmount(ItemStack is, Player player){
+        short maxDurability = is.getType().getMaxDurability();
+        int repairAmount = 0;
+
+        if (ItemChecks.isShovel(is)) {
+            repairAmount = maxDurability;
+        }
+        else if (ItemChecks.isHoe(is) || ItemChecks.isSword(is) || is.getType().equals(Material.SHEARS) || is.getType().equals(Material.FISHING_ROD)) {
+            repairAmount = maxDurability / 2;
+        }
+        else if (ItemChecks.isAxe(is) || ItemChecks.isPickaxe(is) || is.getType().equals(Material.BOW)) {
+            repairAmount = maxDurability / 3;
+        }
+        else if (ItemChecks.isBoots(is)) {
+            repairAmount = maxDurability / 4;
+        }
+        else if (ItemChecks.isHelmet(is)) {
+            repairAmount = maxDurability / 5;
+        }
+        else if (ItemChecks.isPants(is)) {
+            repairAmount = maxDurability / 7;
+        }
+        else if (ItemChecks.isChestplate(is)) {
+            repairAmount = maxDurability / 8;
+        }
+
+        return repairCalculate(player, is.getDurability(), repairAmount);
+    }
+
+    /**
+     * Gets the base durability amount to repair a custom item.
+     *
+     * @param is The custom item being repaired
+     * @param player The player repairing the custom item
+     * @return The final amount of durability repaired to the custom item
+     */
+    private static short getCustomRepairAmount(ItemStack is, Player player) {
+        short maxDurability = 0;
+        int materialsRequired = 0;
+        int repairAmount = 0;
+
+        CustomTool tool = ModChecks.getToolFromItemStack(is);
+        CustomItem armor = ModChecks.getArmorFromItemStack(is);
+
+        if (tool != null) {
+            maxDurability = tool.getDurability();
+            materialsRequired = tool.getRepairQuantity();
+        }
+        else if (armor != null) {
+            maxDurability = armor.getDurability();
+            materialsRequired = armor.getRepairQuantity();
+        }
+
+        repairAmount = maxDurability / materialsRequired;
+
+        return repairCalculate(player, is.getDurability(), repairAmount);
+    }
+
+    /**
+     * Informs a player that the repair has failed.
+     *
+     * @param is The item being repaired
+     * @param player The player repairing the item
+     */
+    private static void needMoreVespeneGas(ItemStack is, Player player) {
+        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
+
+        if (is.getAmount() != 1) {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.StackedItems"));
+        }
+        else {
+            if (ItemChecks.isDiamondTool(is) || ItemChecks.isDiamondArmor(is)) {
+                if (skillLevel < configInstance.getRepairDiamondLevelRequirement()) {
+                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptDiamond"));
+                }
+                else {
+                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.BLUE + Misc.prettyItemString(configInstance.getRepairDiamondMaterial()));
+                }
+            }
+            else if (ItemChecks.isIronTool(is) || ItemChecks.isIronArmor(is)) {
+                if (skillLevel < configInstance.getRepairIronLevelRequirement()) {
+                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptIron"));
+                }
+                else {
+                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore")+ " " + ChatColor.GRAY + Misc.prettyItemString(configInstance.getRepairIronMaterial()));
+                }
+            }
+            else if (ItemChecks.isGoldTool(is) || ItemChecks.isGoldArmor(is)) {
+                if (skillLevel < configInstance.getRepairGoldLevelRequirement()) {
+                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptGold"));
+                }
+                else {
+                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.GOLD + Misc.prettyItemString(configInstance.getRepairGoldMaterial()));
+                }
+            }
+            else if (ItemChecks.isStoneTool(is)) {
+                if (skillLevel < configInstance.getRepairStoneLevelRequirement()) {
+                    player.sendMessage(LocaleLoader.getString("Repair.Skills.AdeptStone"));
+                }
+                else {
+                    player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.GRAY + Misc.prettyItemString(configInstance.getRepairStoneMaterial()));
+                }
+            }
+            else if (ItemChecks.isWoodTool(is)) {
+                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.DARK_GREEN + Misc.prettyItemString(configInstance.getRepairWoodMaterial()));
+            }
+            else if (ItemChecks.isLeatherArmor(is)) {
+                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.YELLOW + Misc.prettyItemString(configInstance.getRepairLeatherMaterial()));
+            }
+            else if (ItemChecks.isStringTool(is)) {
+                player.sendMessage(LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.YELLOW + Misc.prettyItemString(configInstance.getRepairStringMaterial()));
+            }
+            else {
+                player.sendMessage("You do not have the material needed to repair this item!"); //TODO: Use locale
+            }
+        }
+    }
+
+    /**
+     * Checks for Super Repair bonus.
+     *
+     * @param player The player repairing an item
+     * @return true if bonus granted, false otherwise
+     */
+    public static boolean checkPlayerProcRepair(Player player) {
+        final int MAX_BONUS_LEVEL = 1000;
+
+        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
+
+        if ((skillLevel > MAX_BONUS_LEVEL || random.nextInt(1000) <= skillLevel) && permInstance.repairBonus(player)) {
+            player.sendMessage(LocaleLoader.getString("Repair.Skills.FeltEasy"));
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Repairs an item.
+     *
+     * @param player The player repairing an item
+     * @param item The item being repaired
+     * @param repairMaterial The repair reagent
+     */
+    private static void repairItem(Player player, ItemStack item, ItemStack repairMaterial) {
+        short initialDurability = item.getDurability();
+        short newDurability = getRepairAmount(item, player);
+        PlayerInventory inventory = player.getInventory();
+
+        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (initialDurability - newDurability), repairMaterial, item);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        if (event.isCancelled()) {
+            return;
+        }
+
+        if (repairMaterial.getType().equals(Material.WOOD)) {
+            removeWood(inventory);
+        }
+        else {
+            inventory.removeItem(repairMaterial);
+        }
+
+        /* Handle the enchants */
+        if (configInstance.getArcaneForgingEnchantLossEnabled() && !permInstance.arcaneBypass(player)) {
+            addEnchants(player, item);
+        }
+
+        item.setDurability(newDurability);
+    }
+
+    /**
+     * Repairs a custom item.
+     *
+     * @param player The player repairing an item
+     * @param item The custom item being repaired
+     * @param repairMaterial The repair reagent
+     */
+    private static void repairCustomItem(Player player, ItemStack item, ItemStack repairMaterial) {
+        short initialDurability = item.getDurability();
+        short newDurability = getCustomRepairAmount(item, player);
+        PlayerInventory inventory = player.getInventory();
+
+        McMMOPlayerRepairCheckEvent event = new McMMOPlayerRepairCheckEvent(player, (short) (initialDurability - newDurability), repairMaterial, item);
+        mcMMO.p.getServer().getPluginManager().callEvent(event);
+
+        if (event.isCancelled()) {
+            return;
+        }
+
+        inventory.removeItem(repairMaterial);
+
+        if (configInstance.getArcaneForgingEnchantLossEnabled() && !permInstance.arcaneBypass(player)) {
+            addEnchants(player, item);
+        }
+
+        item.setDurability(newDurability);
+    }
+
+    /**
+     * Handles notifications for placing an anvil.
+     *
+     * @param player The player placing the anvil
+     * @param anvilID The item ID of the anvil block
+     */
+    public static void placedAnvilCheck(Player player, int anvilID) {
+        PlayerProfile PP = Users.getProfile(player);
+
+        if (!PP.getPlacedAnvil()) {
+            if (configInstance.spoutEnabled) {
+                SpoutPlayer sPlayer = SpoutManager.getPlayer(player);
+
+                if (sPlayer.isSpoutCraftEnabled()) {
+                    sPlayer.sendNotification("[mcMMO] Anvil Placed", "Right click to repair!", Material.getMaterial(anvilID)); //TODO: Use Locale
+                }
+            }
+            else {
+                player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
+            }
+
+            PP.togglePlacedAnvil();
+        }
+    }
+
+    /**
+     * Removes wood from a player's inventory on repair. Needed due to wood having multiple possible data values.
+     *
+     * @param inventory The inventory to remove wood from
+     */
+    private static void removeWood(PlayerInventory inventory) {
+        //TODO: Make this less hackish once there's a better way to do it...
+        int slot = inventory.first(Material.WOOD);
+        ItemStack item = inventory.getItem(slot);
+        item.setAmount(item.getAmount() - 1);
+        inventory.setItem(slot, item);
+    }
+}

+ 156 - 1
src/main/java/com/gmail/nossr50/skills/repair/SimpleRepairManager.java

@@ -3,8 +3,21 @@ package com.gmail.nossr50.skills.repair;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 
 
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.PlayerProfile;
+import com.gmail.nossr50.datatypes.SkillType;
+import com.gmail.nossr50.events.skills.McMMOPlayerRepairCheckEvent;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.util.Misc;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.Users;
 
 
 public class SimpleRepairManager implements RepairManager {
 public class SimpleRepairManager implements RepairManager {
     private HashMap<Integer, Repairable> repairables;
     private HashMap<Integer, Repairable> repairables;
@@ -42,6 +55,148 @@ public class SimpleRepairManager implements RepairManager {
 
 
     @Override
     @Override
     public void handleRepair(Player player, ItemStack item) {
     public void handleRepair(Player player, ItemStack item) {
-        // TODO Auto-generated method stub
+        // Load some variables for use
+        PlayerProfile PP = Users.getProfile(player);
+        short startDurability = item.getDurability();
+        PlayerInventory inventory = player.getInventory();
+        int skillLevel = PP.getSkillLevel(SkillType.REPAIR);
+        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;
+        }
+
+        // TODO: Level check
+
+        // Check if they have the proper material to repair with
+        if(!inventory.contains(repairable.getRepairMaterialId())) {
+            String message = LocaleLoader.getString("Skills.NeedMore") + " " + ChatColor.YELLOW + Misc.prettyItemString(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;
+        }
+
+        // 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;
+        }
+
+        // Lets get down to business,
+        // To defeat, the huns.
+        int baseRepairAmount = repairable.getBaseRepairDurability();
+        short newDurability = Repair.repairCalculate(player, skillLevel, startDurability, baseRepairAmount);
+
+        // 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("mcMMO encountered an error attempting to repair this item!");  // TODO: Locale ?
+        }
+
+        // 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 (Config.getInstance().getArcaneForgingEnchantLossEnabled() && !Permissions.getInstance().arcaneBypass(player)) {
+            // Generalize away enchantment work
+            Repair.addEnchants(player, item);
+        }
+
+        // Remove the item
+        removeOneFrom(inventory, repairItemLocation);
+
+        // 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);
+        if(item.getAmount() > 1) {
+            item.setAmount(item.getAmount() - 1);
+        } else {
+            item = new ItemStack(0);
+        }
+
+        // I suspect this may not be needed, but I don't think it hurts
+        inventory.setItem(index, 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;
+        } else {
+            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;
+
+        ItemStack[] contents = inventory.getContents();
+        for(int i = 0; i < contents.length; i++) {
+            ItemStack item = contents[i];
+            if(item.getTypeId() == itemId) {
+                if(item.getData().getData() == metadata) {
+                    location = i;
+                }
+            }
+            if(location != -1) break;
+        }
+
+        return location;
     }
     }
 }
 }