From c35c3c0dabe4709206ba656dc0f8ad422d0f0791 Mon Sep 17 00:00:00 2001
From: TfT_02 <tft_02@hotmail.com>
Date: Sat, 14 Dec 2013 14:27:50 +0100
Subject: [PATCH] A whole bunch of more work to convert Salvage to a child
 skill

---
 .../commands/skills/RepairCommand.java        |  15 +-
 .../commands/skills/SalvageCommand.java       |  12 +-
 .../gmail/nossr50/config/AdvancedConfig.java  |   6 +-
 .../java/com/gmail/nossr50/config/Config.java |   7 +-
 .../config/experience/ExperienceConfig.java   |   4 +-
 .../config/mods/CustomArmorConfig.java        |   6 +-
 .../nossr50/config/mods/CustomToolConfig.java |   6 +-
 .../config/skills/repair/RepairConfig.java    |  33 ++-
 .../config/skills/salvage/SalvageConfig.java  | 159 +++++++++++++
 .../skills/salvage/SalvageConfigManager.java  |  42 ++++
 .../nossr50/datatypes/player/McMMOPlayer.java |   1 -
 .../nossr50/datatypes/skills/ItemType.java    |   7 +
 .../datatypes/skills/MaterialType.java        |  43 ++++
 .../nossr50/listeners/BlockListener.java      |  13 +-
 .../nossr50/listeners/PlayerListener.java     |  18 +-
 src/main/java/com/gmail/nossr50/mcMMO.java    |  28 ++-
 .../gmail/nossr50/skills/repair/Repair.java   |   3 -
 .../nossr50/skills/repair/RepairManager.java  |  69 ++----
 .../repair/repairables/RepairItemType.java    |  33 ---
 .../repairables/RepairMaterialType.java       |  84 -------
 .../skills/repair/repairables/Repairable.java |   7 +-
 .../repair/repairables/RepairableFactory.java |   7 +-
 .../repair/repairables/SimpleRepairable.java  |  13 +-
 .../gmail/nossr50/skills/salvage/Salvage.java |  55 +----
 .../skills/salvage/SalvageManager.java        | 130 +++++++----
 .../salvage/salvageables/Salvageable.java     |  82 +++++++
 .../salvageables/SalvageableFactory.java      |  17 ++
 .../salvageables/SalvageableManager.java      |  49 ++++
 .../salvageables/SimpleSalvageable.java       |  80 +++++++
 .../SimpleSalvageableManager.java             |  48 ++++
 .../com/gmail/nossr50/util/Permissions.java   |  20 +-
 .../gmail/nossr50/util/skills/SkillUtils.java |  30 ++-
 src/main/resources/advanced.yml               |   4 -
 src/main/resources/config.yml                 |   8 +-
 .../resources/locale/locale_en_US.properties  |  30 ++-
 src/main/resources/repair.vanilla.yml         |   2 +-
 src/main/resources/salvage.vanilla.yml        | 213 ++++++++++++++++++
 37 files changed, 1008 insertions(+), 376 deletions(-)
 create mode 100644 src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java
 create mode 100644 src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java
 create mode 100644 src/main/java/com/gmail/nossr50/datatypes/skills/ItemType.java
 create mode 100644 src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java
 delete mode 100644 src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairItemType.java
 delete mode 100644 src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairMaterialType.java
 create mode 100644 src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java
 create mode 100644 src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java
 create mode 100644 src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java
 create mode 100644 src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java
 create mode 100644 src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java
 create mode 100644 src/main/resources/salvage.vanilla.yml

diff --git a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
index 30ebf33e5..aa6148940 100644
--- a/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
+++ b/src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
@@ -7,6 +7,7 @@ import org.bukkit.Material;
 import org.bukkit.entity.Player;
 
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.skills.SecondaryAbility;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -76,13 +77,13 @@ public class RepairCommand extends SkillCommand {
         canSuperRepair = Permissions.secondaryAbilityEnabled(player, SecondaryAbility.SUPER_REPAIR);
         canMasterRepair = Permissions.secondaryAbilityEnabled(player, SecondaryAbility.REPAIR_MASTERY);
         canArcaneForge = Permissions.secondaryAbilityEnabled(player, SecondaryAbility.ARCANE_FORGING);
-        canRepairDiamond = Permissions.repairDiamond(player);
-        canRepairGold = Permissions.repairGold(player);
-        canRepairIron = Permissions.repairIron(player);
-        canRepairStone = Permissions.repairStone(player);
-        canRepairString = Permissions.repairString(player);
-        canRepairLeather = Permissions.repairLeather(player);
-        canRepairWood = Permissions.repairWood(player);
+        canRepairDiamond = Permissions.repairMaterialType(player, MaterialType.DIAMOND);
+        canRepairGold = Permissions.repairMaterialType(player, MaterialType.GOLD);
+        canRepairIron = Permissions.repairMaterialType(player, MaterialType.IRON);
+        canRepairStone = Permissions.repairMaterialType(player, MaterialType.STONE);
+        canRepairString = Permissions.repairMaterialType(player, MaterialType.STRING);
+        canRepairLeather = Permissions.repairMaterialType(player, MaterialType.LEATHER);
+        canRepairWood = Permissions.repairMaterialType(player, MaterialType.WOOD);
         arcaneBypass = Permissions.arcaneBypass(player);
     }
 
diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java
index bbffcddc2..67b245214 100644
--- a/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java
+++ b/src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java
@@ -51,26 +51,26 @@ public class SalvageCommand extends SkillCommand {
     @Override
     protected List<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
         List<String> messages = new ArrayList<String>();
+        SalvageManager salvageManager = UserManager.getPlayer(player).getSalvageManager();
+
         if (canAdvancedSalvage) {
             if (skillValue < Salvage.advancedSalvageUnlockLevel) {
                 messages.add(LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Salvage.Ability.Locked.0", Salvage.advancedSalvageUnlockLevel)));
             }
             else {
-                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Ability.Bonus.0"), LocaleLoader.getString("Salvage.Ability.Bonus.1")));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Ability.Bonus.0"), LocaleLoader.getString("Salvage.Ability.Bonus.1", percent.format(salvageManager.getMaxSalvagePercentage()))));
             }
         }
 
         if (canArcaneSalvage) {
-            SalvageManager salvageManager = UserManager.getPlayer(player).getSalvageManager();
-
-            messages.add(LocaleLoader.getString("Salvage.Arcane.Rank", salvageManager.getArcaneSalvageRank(), Salvage.Tier.EIGHT.toNumerical()));
+            messages.add(LocaleLoader.getString("Salvage.Arcane.Rank", salvageManager.getArcaneSalvageRank(), Salvage.Tier.values().length));
 
             if (Salvage.arcaneSalvageEnchantLoss) {
-                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractFull"), salvageManager.getExtractFullEnchantChance()));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractFull"), percent.format(salvageManager.getExtractFullEnchantChance() / 100)));
             }
 
             if (Salvage.arcaneSalvageDowngrades) {
-                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractPartial"), salvageManager.getExtractPartialEnchantChance()));
+                messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Salvage.Arcane.ExtractPartial"), percent.format(salvageManager.getExtractPartialEnchantChance() / 100)));
             }
         }
 
diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java
index c4c57e046..5810d8ae0 100644
--- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java
@@ -767,8 +767,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     /* REPAIR */
     public double getRepairMasteryMaxBonus() { return config.getDouble("Skills.Repair.RepairMastery.MaxBonusPercentage", 200.0D); }
     public int getRepairMasteryMaxLevel() { return config.getInt("Skills.Repair.RepairMastery.MaxBonusLevel", 1000); }
-    public double getSuperRepairChanceMax() { return config.getDouble("Skills.Repair.SuperRepair.ChanceMax", 100.0D); }
-    public int getSuperRepairMaxLevel() { return config.getInt("Skills.Repair.SuperRepair.MaxBonusLevel", 1000); }
 
     /* Arcane Forging */
     public int getArcaneForgingRankLevel(ArcaneForging.Tier tier) { return config.getInt("Skills.Repair.ArcaneForging.Rank_Levels.Rank_" + tier.toNumerical()); }
@@ -789,8 +787,8 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     public boolean getArcaneSalvageEnchantLossEnabled() { return config.getBoolean("Skills.Salvage.ArcaneSalvage.EnchantLossEnabled", true); }
 
     public int getArcaneSalvageRankLevel(Salvage.Tier tier) { return config.getInt("Skills.Salvage.ArcaneSalvage.Rank_Levels.Rank_" + tier.toNumerical()); }
-    public int getArcaneSalvageExtractFullEnchantsChance(Salvage.Tier tier) { return config.getInt("Skills.Salvage.ArcaneSalvage.ExtractFullEnchant.Rank_" + tier.toNumerical()); }
-    public int getArcaneSalvageExtractPartialEnchantsChance(Salvage.Tier tier) { return config.getInt("Skills.Salvage.ArcaneSalvage.ExtractPartialEnchant.Rank_" + tier.toNumerical()); }
+    public double getArcaneSalvageExtractFullEnchantsChance(Salvage.Tier tier) { return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractFullEnchant.Rank_" + tier.toNumerical()); }
+    public double getArcaneSalvageExtractPartialEnchantsChance(Salvage.Tier tier) { return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractPartialEnchant.Rank_" + tier.toNumerical()); }
 
     /* SMELTING */
     public int getBurnModifierMaxLevel() { return config.getInt("Skills.Smelting.FuelEfficiency.MaxBonusLevel", 1000); }
diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java
index 10528fccf..a8fb95f6d 100644
--- a/src/main/java/com/gmail/nossr50/config/Config.java
+++ b/src/main/java/com/gmail/nossr50/config/Config.java
@@ -466,9 +466,10 @@ public class Config extends AutoUpdateConfigLoader {
 
     /* Salvage */
     public boolean getSalvageAnvilMessagesEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Messages", true); }
-    public Material getSalvageAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Repair.Salvage_Anvil_ID", "GOLD_BLOCK")); }
-    public boolean getSalvageTools() { return config.getBoolean("Skills.Salvage.Salvage_tools", true); }
-    public boolean getSalvageArmor() { return config.getBoolean("Skills.Salvage.Salvage_armor", true); }
+    public boolean getSalvageAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Placed_Sounds", true); }
+    public boolean getSalvageAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Use_Sounds", true); }
+    public Material getSalvageAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); }
+    public boolean getSalvageConfirmRequired() { return config.getBoolean("Skills.Salvage.Confirm_Required", true); }
 
     /* Unarmed */
     public boolean getUnarmedBlockCrackerSmoothbrickToCracked() { return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true); }
diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java
index 2e883a2a3..2412c7986 100644
--- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java
@@ -8,8 +8,8 @@ import org.bukkit.entity.EntityType;
 
 import com.gmail.nossr50.config.AutoUpdateConfigLoader;
 import com.gmail.nossr50.datatypes.experience.FormulaType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.skills.SkillType;
-import com.gmail.nossr50.skills.repair.repairables.RepairMaterialType;
 import com.gmail.nossr50.util.StringUtils;
 
 public class ExperienceConfig extends AutoUpdateConfigLoader {
@@ -216,7 +216,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
 
     /* Repair */
     public double getRepairXPBase() { return config.getDouble("Experience.Repair.Base", 1000.0); }
-    public double getRepairXP(RepairMaterialType repairMaterialType) { return config.getDouble("Experience.Repair." + StringUtils.getCapitalized(repairMaterialType.toString())); }
+    public double getRepairXP(MaterialType repairMaterialType) { return config.getDouble("Experience.Repair." + StringUtils.getCapitalized(repairMaterialType.toString())); }
 
     /* Taming */
     public int getTamingXPHorse() { return config.getInt("Experience.Taming.Animal_Taming.Horse", 1000); }
diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java
index 410f74f4f..1345e8b46 100644
--- a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java
@@ -9,8 +9,8 @@ import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.inventory.ItemStack;
 
 import com.gmail.nossr50.config.ConfigLoader;
-import com.gmail.nossr50.skills.repair.repairables.RepairItemType;
-import com.gmail.nossr50.skills.repair.repairables.RepairMaterialType;
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
 import com.gmail.nossr50.util.skills.SkillUtils;
@@ -91,7 +91,7 @@ public class CustomArmorConfig extends ConfigLoader {
                     durability = (short) config.getInt(armorType + "." + armorName + ".Durability", 70);
                 }
 
-                repairables.add(RepairableFactory.getRepairable(armorMaterial, repairMaterial, repairData, 0, repairQuantity, durability, RepairItemType.ARMOR, RepairMaterialType.OTHER, 1.0));
+                repairables.add(RepairableFactory.getRepairable(armorMaterial, repairMaterial, repairData, 0, repairQuantity, durability, ItemType.ARMOR, MaterialType.OTHER, 1.0));
             }
 
             materialList.add(armorMaterial);
diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java
index 5b9aa6de4..e02709401 100644
--- a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java
@@ -10,9 +10,9 @@ import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.inventory.ItemStack;
 
 import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.mods.CustomTool;
-import com.gmail.nossr50.skills.repair.repairables.RepairItemType;
-import com.gmail.nossr50.skills.repair.repairables.RepairMaterialType;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
 import com.gmail.nossr50.util.skills.SkillUtils;
@@ -99,7 +99,7 @@ public class CustomToolConfig extends ConfigLoader {
                     durability = (short) config.getInt(toolType + "." + toolName + ".Durability", 60);
                 }
 
-                repairables.add(RepairableFactory.getRepairable(toolMaterial, repairMaterial, repairData, 0, repairQuantity, durability, RepairItemType.TOOL, RepairMaterialType.OTHER, 1.0));
+                repairables.add(RepairableFactory.getRepairable(toolMaterial, repairMaterial, repairData, 0, repairQuantity, durability, ItemType.TOOL, MaterialType.OTHER, 1.0));
             }
 
             double multiplier = config.getDouble(toolType + "." + toolName + ".XP_Modifier", 1.0);
diff --git a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java
index 3986a6c18..a3a0550f9 100644
--- a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java
+++ b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java
@@ -9,9 +9,8 @@ import org.bukkit.configuration.ConfigurationSection;
 import org.bukkit.inventory.ItemStack;
 
 import com.gmail.nossr50.config.ConfigLoader;
-import com.gmail.nossr50.skills.repair.Repair;
-import com.gmail.nossr50.skills.repair.repairables.RepairItemType;
-import com.gmail.nossr50.skills.repair.repairables.RepairMaterialType;
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.skills.repair.repairables.RepairableFactory;
 import com.gmail.nossr50.util.ItemUtils;
@@ -49,37 +48,37 @@ public class RepairConfig extends ConfigLoader {
             }
 
             // Repair Material Type
-            RepairMaterialType repairMaterialType = RepairMaterialType.OTHER;
+            MaterialType repairMaterialType = MaterialType.OTHER;
             String repairMaterialTypeString = config.getString("Repairables." + key + ".MaterialType", "OTHER");
 
             if (!config.contains("Repairables." + key + ".MaterialType") && itemMaterial != null) {
                 ItemStack repairItem = new ItemStack(itemMaterial);
 
                 if (ItemUtils.isWoodTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.WOOD;
+                    repairMaterialType = MaterialType.WOOD;
                 }
                 else if (ItemUtils.isStoneTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.STONE;
+                    repairMaterialType = MaterialType.STONE;
                 }
                 else if (ItemUtils.isStringTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.STRING;
+                    repairMaterialType = MaterialType.STRING;
                 }
                 else if (ItemUtils.isLeatherArmor(repairItem)) {
-                    repairMaterialType = RepairMaterialType.LEATHER;
+                    repairMaterialType = MaterialType.LEATHER;
                 }
                 else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.IRON;
+                    repairMaterialType = MaterialType.IRON;
                 }
                 else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.GOLD;
+                    repairMaterialType = MaterialType.GOLD;
                 }
                 else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
-                    repairMaterialType = RepairMaterialType.DIAMOND;
+                    repairMaterialType = MaterialType.DIAMOND;
                 }
             }
             else {
                 try {
-                    repairMaterialType = RepairMaterialType.valueOf(repairMaterialTypeString);
+                    repairMaterialType = MaterialType.valueOf(repairMaterialTypeString);
                 }
                 catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid MaterialType of " + repairMaterialTypeString);
@@ -88,7 +87,7 @@ public class RepairConfig extends ConfigLoader {
 
             // Repair Material
             String repairMaterialName = config.getString("Repairables." + key + ".RepairMaterial");
-            Material repairMaterial = (repairMaterialName == null ? repairMaterialType.getDefaultRepairMaterial() : Material.matchMaterial(repairMaterialName));
+            Material repairMaterial = (repairMaterialName == null ? repairMaterialType.getDefaultMaterial() : Material.matchMaterial(repairMaterialName));
 
             if (repairMaterial == null) {
                 reason.add(key + " has an invalid repair material: " + repairMaterialName);
@@ -106,22 +105,22 @@ public class RepairConfig extends ConfigLoader {
             }
 
             // Item Type
-            RepairItemType repairItemType = RepairItemType.OTHER;
+            ItemType repairItemType = ItemType.OTHER;
             String repairItemTypeString = config.getString("Repairables." + key + ".ItemType", "OTHER");
 
             if (!config.contains("Repairables." + key + ".ItemType") && itemMaterial != null) {
                 ItemStack repairItem = new ItemStack(itemMaterial);
 
                 if (ItemUtils.isMinecraftTool(repairItem)) {
-                    repairItemType = RepairItemType.TOOL;
+                    repairItemType = ItemType.TOOL;
                 }
                 else if (ItemUtils.isArmor(repairItem)) {
-                    repairItemType = RepairItemType.ARMOR;
+                    repairItemType = ItemType.ARMOR;
                 }
             }
             else {
                 try {
-                    repairItemType = RepairItemType.valueOf(repairItemTypeString);
+                    repairItemType = ItemType.valueOf(repairItemTypeString);
                 }
                 catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid ItemType of " + repairItemTypeString);
diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java
new file mode 100644
index 000000000..479456101
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java
@@ -0,0 +1,159 @@
+package com.gmail.nossr50.config.skills.salvage;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.inventory.ItemStack;
+
+import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
+import com.gmail.nossr50.skills.salvage.salvageables.SalvageableFactory;
+import com.gmail.nossr50.util.ItemUtils;
+import com.gmail.nossr50.util.skills.SkillUtils;
+
+public class SalvageConfig extends ConfigLoader {
+    private List<Salvageable> salvageables;
+
+    public SalvageConfig(String fileName) {
+        super(fileName);
+        loadKeys();
+    }
+
+    @Override
+    protected void loadKeys() {
+        salvageables = new ArrayList<Salvageable>();
+
+        ConfigurationSection section = config.getConfigurationSection("Salvageables");
+        Set<String> keys = section.getKeys(false);
+
+        for (String key : keys) {
+            // Validate all the things!
+            List<String> reason = new ArrayList<String>();
+
+            // Item Material
+            Material itemMaterial = Material.matchMaterial(key);
+
+            if (itemMaterial == null) {
+                reason.add("Invalid material: " + key);
+            }
+
+            // Repair Material Type
+            MaterialType salvageMaterialType = MaterialType.OTHER;
+            String repairMaterialTypeString = config.getString("Salvageables." + key + ".MaterialType", "OTHER");
+
+            if (!config.contains("Salvageables." + key + ".MaterialType") && itemMaterial != null) {
+                ItemStack repairItem = new ItemStack(itemMaterial);
+
+                if (ItemUtils.isWoodTool(repairItem)) {
+                    salvageMaterialType = MaterialType.WOOD;
+                }
+                else if (ItemUtils.isStoneTool(repairItem)) {
+                    salvageMaterialType = MaterialType.STONE;
+                }
+                else if (ItemUtils.isStringTool(repairItem)) {
+                    salvageMaterialType = MaterialType.STRING;
+                }
+                else if (ItemUtils.isLeatherArmor(repairItem)) {
+                    salvageMaterialType = MaterialType.LEATHER;
+                }
+                else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
+                    salvageMaterialType = MaterialType.IRON;
+                }
+                else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
+                    salvageMaterialType = MaterialType.GOLD;
+                }
+                else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
+                    salvageMaterialType = MaterialType.DIAMOND;
+                }
+            }
+            else {
+                try {
+                    salvageMaterialType = MaterialType.valueOf(repairMaterialTypeString);
+                }
+                catch (IllegalArgumentException ex) {
+                    reason.add(key + " has an invalid MaterialType of " + repairMaterialTypeString);
+                }
+            }
+
+            // Salvage Material
+            String salvageMaterialName = config.getString("Salvageables." + key + ".SalvageMaterial");
+            Material salvageMaterial = (salvageMaterialName == null ? salvageMaterialType.getDefaultMaterial() : Material.matchMaterial(salvageMaterialName));
+
+            if (salvageMaterial == null) {
+                reason.add(key + " has an invalid salvage material: " + salvageMaterialName);
+            }
+
+            // Maximum Durability
+            short maximumDurability = (itemMaterial != null ? itemMaterial.getMaxDurability() : (short) config.getInt("Salvageables." + key + ".MaximumDurability"));
+
+            // Item Type
+            ItemType salvageItemType = ItemType.OTHER;
+            String salvageItemTypeString = config.getString("Salvageables." + key + ".ItemType", "OTHER");
+
+            if (!config.contains("Salvageables." + key + ".ItemType") && itemMaterial != null) {
+                ItemStack salvageItem = new ItemStack(itemMaterial);
+
+                if (ItemUtils.isMinecraftTool(salvageItem)) {
+                    salvageItemType = ItemType.TOOL;
+                }
+                else if (ItemUtils.isArmor(salvageItem)) {
+                    salvageItemType = ItemType.ARMOR;
+                }
+            }
+            else {
+                try {
+                    salvageItemType = ItemType.valueOf(salvageItemTypeString);
+                }
+                catch (IllegalArgumentException ex) {
+                    reason.add(key + " has an invalid ItemType of " + salvageItemTypeString);
+                }
+            }
+
+            byte salvageMetadata = (byte) config.getInt("Salvageables." + key + ".SalvageMaterialMetadata", -1);
+            int minimumLevel = config.getInt("Salvageables." + key + ".MinimumLevel");
+            double xpMultiplier = config.getDouble("Salvageables." + key + ".XpMultiplier", 1);
+
+            if (minimumLevel < 0) {
+                reason.add(key + " has an invalid MinimumLevel of " + minimumLevel);
+            }
+
+            // Maximum Quantity
+            int maximumQuantity = (itemMaterial != null ? SkillUtils.getRepairAndSalvageQuantities(new ItemStack(itemMaterial), salvageMaterial, salvageMetadata) : config.getInt("Repairables." + key + ".MaximumQuantity", 2));
+
+            if (maximumQuantity <= 0 && itemMaterial != null) {
+                maximumQuantity = config.getInt("Salvageables." + key + ".MaximumQuantity", 2);
+            }
+
+            if (maximumQuantity <= 0) {
+                reason.add("Minimum quantity of " + key + " must be greater than 0!");
+            }
+
+            if (noErrorsInSalvageable(reason)) {
+                Salvageable salvageable = SalvageableFactory.getSalvageable(itemMaterial, salvageMaterial, salvageMetadata, minimumLevel, maximumQuantity, maximumDurability, salvageItemType, salvageMaterialType, xpMultiplier);
+                salvageables.add(salvageable);
+            }
+        }
+    }
+
+    protected List<Salvageable> getLoadedSalvageables() {
+        return salvageables == null ? new ArrayList<Salvageable>() : salvageables;
+    }
+
+    private boolean noErrorsInSalvageable(List<String> issues) {
+        if (!issues.isEmpty()) {
+            plugin.getLogger().warning("Errors have been found in: " + fileName);
+            plugin.getLogger().warning("The following issues were found:");
+        }
+
+        for (String issue : issues) {
+            plugin.getLogger().warning(issue);
+        }
+
+        return issues.isEmpty();
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java
new file mode 100644
index 000000000..9e50b7e05
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java
@@ -0,0 +1,42 @@
+package com.gmail.nossr50.config.skills.salvage;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
+
+public class SalvageConfigManager {
+    private final List<Salvageable> salvageables = new ArrayList<Salvageable>();
+
+    public SalvageConfigManager(mcMMO plugin) {
+        Pattern pattern = Pattern.compile("salvage\\.(?:.+)\\.yml");
+        File dataFolder = plugin.getDataFolder();
+        File vanilla = new File(dataFolder, "salvage.vanilla.yml");
+
+        if (!vanilla.exists()) {
+            plugin.saveResource("salvage.vanilla.yml", false);
+        }
+
+        for (String fileName : dataFolder.list()) {
+            if (!pattern.matcher(fileName).matches()) {
+                continue;
+            }
+
+            File file = new File(dataFolder, fileName);
+
+            if (file.isDirectory()) {
+                continue;
+            }
+
+            SalvageConfig salvageConfig = new SalvageConfig(fileName);
+            salvageables.addAll(salvageConfig.getLoadedSalvageables());
+        }
+    }
+
+    public List<Salvageable> getLoadedSalvageables() {
+        return salvageables;
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
index eb6987ddc..aa05c978c 100644
--- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
+++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
@@ -41,7 +41,6 @@ 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.salvage.Salvage;
 import com.gmail.nossr50.skills.salvage.SalvageManager;
 import com.gmail.nossr50.skills.smelting.SmeltingManager;
 import com.gmail.nossr50.skills.swords.SwordsManager;
diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/ItemType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/ItemType.java
new file mode 100644
index 000000000..f0d786d73
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/datatypes/skills/ItemType.java
@@ -0,0 +1,7 @@
+package com.gmail.nossr50.datatypes.skills;
+
+public enum ItemType {
+    ARMOR,
+    TOOL,
+    OTHER;
+}
diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java
new file mode 100644
index 000000000..40efbf5fc
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/datatypes/skills/MaterialType.java
@@ -0,0 +1,43 @@
+package com.gmail.nossr50.datatypes.skills;
+
+import org.bukkit.Material;
+
+public enum MaterialType {
+    STRING,
+    LEATHER,
+    WOOD,
+    STONE,
+    IRON,
+    GOLD,
+    DIAMOND,
+    OTHER;
+
+    public Material getDefaultMaterial() {
+        switch (this) {
+            case STRING:
+                return Material.STRING;
+
+            case LEATHER:
+                return Material.LEATHER;
+
+            case WOOD:
+                return Material.WOOD;
+
+            case STONE:
+                return Material.COBBLESTONE;
+
+            case IRON:
+                return Material.IRON_INGOT;
+
+            case GOLD:
+                return Material.GOLD_INGOT;
+
+            case DIAMOND:
+                return Material.DIAMOND;
+
+            case OTHER:
+            default:
+                return null;
+        }
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
index fecf81c84..9e6430bf7 100644
--- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
@@ -37,6 +37,8 @@ import com.gmail.nossr50.skills.excavation.ExcavationManager;
 import com.gmail.nossr50.skills.herbalism.Herbalism;
 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.salvage.Salvage;
 import com.gmail.nossr50.skills.smelting.SmeltingManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
 import com.gmail.nossr50.util.BlockUtils;
@@ -121,10 +123,13 @@ public class BlockListener implements Listener {
             mcMMO.getPlaceStore().setTrue(blockState);
         }
 
-        if (BlockUtils.isMcMMOAnvil(blockState)) {
-            McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
-            mcMMOPlayer.getRepairManager().placedAnvilCheck(blockState.getType());
-            mcMMOPlayer.getSalvageManager().placedAnvilCheck(blockState.getType());
+        McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
+
+        if (blockState.getType() == Repair.anvilMaterial) {
+            mcMMOPlayer.getRepairManager().placedAnvilCheck();
+        }
+        else if (blockState.getType() == Salvage.anvilMaterial) {
+            mcMMOPlayer.getSalvageManager().placedAnvilCheck();
         }
     }
 
diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
index 9e96af235..df0279a7d 100644
--- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
+++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
@@ -449,18 +449,18 @@ public class PlayerListener implements Listener {
                         event.setCancelled(true);
 
                         // Make sure the player knows what he's doing when trying to repair an enchanted item
-                        if (!(heldItem.getEnchantments().size() > 0) || repairManager.checkConfirmation(type, true)) {
+                        if (!(heldItem.getEnchantments().size() > 0) || repairManager.checkConfirmation(true)) {
                             repairManager.handleRepair(heldItem);
                             player.updateInventory();
                         }
                     }
                     /* SALVAGE CHECKS */
-                    else if (type == Salvage.anvilMaterial && SkillType.SALVAGE.getPermissions(player) && Salvage.isSalvageable(heldItem)) {
+                    else if (type == Salvage.anvilMaterial && SkillType.SALVAGE.getPermissions(player) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) {
                         SalvageManager salvageManager = UserManager.getPlayer(player).getSalvageManager();
                         event.setCancelled(true);
 
                         // Make sure the player knows what he's doing when trying to salvage an enchanted item
-                        if (!(heldItem.getEnchantments().size() > 0) || mcMMOPlayer.getRepairManager().checkConfirmation(type, true)) {
+                        if (!(heldItem.getEnchantments().size() > 0) || salvageManager.checkConfirmation(true)) {
                             salvageManager.handleSalvage(block.getLocation(), heldItem);
                             player.updateInventory();
                         }
@@ -487,18 +487,18 @@ public class PlayerListener implements Listener {
                         RepairManager repairManager = mcMMOPlayer.getRepairManager();
 
                         // Cancel repairing an enchanted item
-                        if (repairManager.checkConfirmation(type, false) && Config.getInstance().getRepairConfirmRequired()) {
-                            repairManager.setLastAnvilUse(Repair.anvilMaterial, 0);
+                        if (repairManager.checkConfirmation(false)) {
+                            repairManager.setLastAnvilUse(0);
                             player.sendMessage(LocaleLoader.getString("Skills.Cancelled", LocaleLoader.getString("Repair.Pretty.Name")));
                         }
                     }
                     /* SALVAGE CHECKS */
-                    else if (type == Salvage.anvilMaterial && SkillType.SALVAGE.getPermissions(player) && Salvage.isSalvageable(heldItem)) {
-                        RepairManager repairManager = mcMMOPlayer.getRepairManager();
+                    else if (type == Salvage.anvilMaterial && SkillType.SALVAGE.getPermissions(player) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) {
+                        SalvageManager salvageManager = mcMMOPlayer.getSalvageManager();
 
                         // Cancel salvaging an enchanted item
-                        if (repairManager.checkConfirmation(type, false) && Config.getInstance().getRepairConfirmRequired()) {
-                            mcMMOPlayer.getSalvageManager().setLastAnvilUse(Repair.anvilMaterial, 0);
+                        if (salvageManager.checkConfirmation(false)) {
+                            salvageManager.setLastAnvilUse(0);
                             player.sendMessage(LocaleLoader.getString("Skills.Cancelled", LocaleLoader.getString("Salvage.Pretty.Name")));
                         }
                     }
diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java
index 1bf756071..68e0b5e59 100644
--- a/src/main/java/com/gmail/nossr50/mcMMO.java
+++ b/src/main/java/com/gmail/nossr50/mcMMO.java
@@ -20,6 +20,7 @@ import com.gmail.nossr50.config.mods.EntityConfigManager;
 import com.gmail.nossr50.config.mods.ToolConfigManager;
 import com.gmail.nossr50.config.skills.alchemy.PotionConfig;
 import com.gmail.nossr50.config.skills.repair.RepairConfigManager;
+import com.gmail.nossr50.config.skills.salvage.SalvageConfigManager;
 import com.gmail.nossr50.config.treasure.TreasureConfig;
 import com.gmail.nossr50.database.DatabaseManager;
 import com.gmail.nossr50.database.DatabaseManagerFactory;
@@ -44,6 +45,9 @@ import com.gmail.nossr50.skills.child.ChildConfig;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import com.gmail.nossr50.skills.repair.repairables.RepairableManager;
 import com.gmail.nossr50.skills.repair.repairables.SimpleRepairableManager;
+import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
+import com.gmail.nossr50.skills.salvage.salvageables.SalvageableManager;
+import com.gmail.nossr50.skills.salvage.salvageables.SimpleSalvageableManager;
 import com.gmail.nossr50.util.ChimaeraWing;
 import com.gmail.nossr50.util.HolidayManager;
 import com.gmail.nossr50.util.LogFilter;
@@ -61,12 +65,13 @@ import net.shatteredlands.shatt.backup.ZipLibrary;
 
 public class mcMMO extends JavaPlugin {
     /* Managers */
-    private static ChunkManager      placeStore;
-    private static RepairableManager repairableManager;
-    private static ModManager        modManager;
-    private static DatabaseManager   databaseManager;
-    private static FormulaManager    formulaManager;
-    private static HolidayManager    holidayManager;
+    private static ChunkManager       placeStore;
+    private static RepairableManager  repairableManager;
+    private static SalvageableManager salvageableManager;
+    private static ModManager         modManager;
+    private static DatabaseManager    databaseManager;
+    private static FormulaManager     formulaManager;
+    private static HolidayManager     holidayManager;
 
     /* File Paths */
     private static String mainDirectory;
@@ -292,6 +297,10 @@ public class mcMMO extends JavaPlugin {
         return repairableManager;
     }
 
+    public static SalvageableManager getSalvageableManager() {
+        return salvageableManager;
+    }
+
     public static DatabaseManager getDatabaseManager() {
         return databaseManager;
     }
@@ -391,6 +400,7 @@ public class mcMMO extends JavaPlugin {
         new ChildConfig();
 
         List<Repairable> repairables = new ArrayList<Repairable>();
+        List<Salvageable> salvageables = new ArrayList<Salvageable>();
 
         if (Config.getInstance().getToolModsEnabled()) {
             new ToolConfigManager(this);
@@ -413,6 +423,12 @@ public class mcMMO extends JavaPlugin {
         repairables.addAll(modManager.getLoadedRepairables());
         repairableManager = new SimpleRepairableManager(repairables.size());
         repairableManager.registerRepairables(repairables);
+
+        // Load salvage configs, make manager and register them at this time
+        SalvageConfigManager sManager = new SalvageConfigManager(this);
+        salvageables.addAll(sManager.getLoadedSalvageables());
+        salvageableManager = new SimpleSalvageableManager(salvageables.size());
+        salvageableManager.registerSalvageables(salvageables);
     }
 
     private void registerEvents() {
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java
index 6ae035ba9..2431a9be4 100644
--- a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java
+++ b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java
@@ -1,7 +1,5 @@
 package com.gmail.nossr50.skills.repair;
 
-import java.util.List;
-
 import org.bukkit.Material;
 
 import com.gmail.nossr50.config.AdvancedConfig;
@@ -12,5 +10,4 @@ public class Repair {
     public static double repairMasteryMaxBonus      = AdvancedConfig.getInstance().getRepairMasteryMaxBonus();
 
     public static Material anvilMaterial  = Config.getInstance().getRepairAnvilMaterial();
-    public static boolean  anvilMessagesEnabled = Config.getInstance().getRepairAnvilMessagesEnabled();
 }
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
index c3e1d6489..06d68330f 100644
--- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
+++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
@@ -22,7 +22,6 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.repair.ArcaneForging.Tier;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
-import com.gmail.nossr50.skills.salvage.Salvage;
 import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
@@ -30,8 +29,8 @@ import com.gmail.nossr50.util.StringUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class RepairManager extends SkillManager {
-    private boolean placedRepairAnvil;
-    private int     lastRepairClick;
+    private boolean placedAnvil;
+    private int     lastClick;
 
     public RepairManager(McMMOPlayer mcMMOPlayer) {
         super(mcMMOPlayer, SkillType.REPAIR);
@@ -39,23 +38,23 @@ public class RepairManager extends SkillManager {
 
     /**
      * Handles notifications for placing an anvil.
-     *
-     * @param anvilType The {@link Material} of the anvil block
      */
-    public void placedAnvilCheck(Material anvilType) {
+    public void placedAnvilCheck() {
         Player player = getPlayer();
 
-        if (getPlacedAnvil(anvilType)) {
+        if (getPlacedAnvil()) {
             return;
         }
 
-        player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
+        if (Config.getInstance().getRepairAnvilMessagesEnabled()) {
+            player.sendMessage(LocaleLoader.getString("Repair.Listener.Anvil"));
+        }
 
         if (Config.getInstance().getRepairAnvilPlaceSoundsEnabled()) {
             player.playSound(player.getLocation(), Sound.ANVIL_LAND, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
         }
 
-        togglePlacedAnvil(anvilType);
+        togglePlacedAnvil();
     }
 
     public void handleRepair(ItemStack item) {
@@ -63,12 +62,12 @@ public class RepairManager extends SkillManager {
         Repairable repairable = mcMMO.getRepairableManager().getRepairable(item.getType());
 
         // Permissions checks on material and item types
-        if (!repairable.getRepairItemType().getPermissions(player)) {
+        if (!Permissions.repairMaterialType(player, repairable.getRepairMaterialType())) {
             player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
             return;
         }
 
-        if (!repairable.getRepairMaterialType().getPermissions(player)) {
+        if (!Permissions.repairMaterialType(player, repairable.getRepairMaterialType())) {
             player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
             return;
         }
@@ -161,9 +160,9 @@ public class RepairManager extends SkillManager {
      *
      * @return true if the player has confirmed using an Anvil
      */
-    public boolean checkConfirmation(Material anvilType, boolean actualize) {
+    public boolean checkConfirmation(boolean actualize) {
         Player player = getPlayer();
-        long lastUse = getLastAnvilUse(anvilType);
+        long lastUse = getLastAnvilUse();
 
         if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getRepairConfirmRequired()) {
             return true;
@@ -173,14 +172,8 @@ public class RepairManager extends SkillManager {
             return false;
         }
 
-        actualizeLastAnvilUse(anvilType);
-
-        if (anvilType == Repair.anvilMaterial) {
-            player.sendMessage(LocaleLoader.getString("Skills.ConfirmOrCancel", LocaleLoader.getString("Repair.Pretty.Name")));
-        }
-        else if (anvilType == Salvage.anvilMaterial) {
-            player.sendMessage(LocaleLoader.getString("Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name")));
-        }
+        actualizeLastAnvilUse();
+        player.sendMessage(LocaleLoader.getString("Skills.ConfirmOrCancel", LocaleLoader.getString("Repair.Pretty.Name")));
 
         return false;
     }
@@ -339,41 +332,27 @@ public class RepairManager extends SkillManager {
      * Repair Anvil Placement
      */
 
-    public boolean getPlacedAnvil(Material anvilType) {
-        if (anvilType == Repair.anvilMaterial) {
-            return placedRepairAnvil;
-        }
-
-        return true;
+    public boolean getPlacedAnvil() {
+        return placedAnvil;
     }
 
-    public void togglePlacedAnvil(Material anvilType) {
-        if (anvilType == Repair.anvilMaterial) {
-            placedRepairAnvil = !placedRepairAnvil;
-        }
+    public void togglePlacedAnvil() {
+        placedAnvil = !placedAnvil;
     }
 
     /*
      * Repair Anvil Usage
      */
 
-    public int getLastAnvilUse(Material anvilType) {
-        if (anvilType == Repair.anvilMaterial) {
-            return lastRepairClick;
-        }
-
-        return 0;
+    public int getLastAnvilUse() {
+        return lastClick;
     }
 
-    public void setLastAnvilUse(Material anvilType, int value) {
-        if (anvilType == Repair.anvilMaterial) {
-            lastRepairClick = value;
-        }
+    public void setLastAnvilUse(int value) {
+        lastClick = value;
     }
 
-    public void actualizeLastAnvilUse(Material anvilType) {
-        if (anvilType == Repair.anvilMaterial) {
-            lastRepairClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
-        }
+    public void actualizeLastAnvilUse() {
+        lastClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
     }
 }
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairItemType.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairItemType.java
deleted file mode 100644
index cff61ebf3..000000000
--- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairItemType.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.gmail.nossr50.skills.repair.repairables;
-
-import org.bukkit.entity.Player;
-
-import com.gmail.nossr50.util.Permissions;
-
-public enum RepairItemType {
-    ARMOR,
-    TOOL,
-    OTHER;
-
-    /**
-     * Get the base permissions associated with this RepairItemType.
-     *
-     * @param player The player to check the permissions for
-     * @return true if the player has permissions, false otherwise
-     */
-    public boolean getPermissions(Player player) {
-        switch (this) {
-            case ARMOR:
-                return Permissions.repairArmor(player);
-
-            case TOOL:
-                return Permissions.repairTools(player);
-
-            case OTHER:
-                return Permissions.repairOtherItems(player);
-
-            default:
-                return false;
-        }
-    }
-}
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairMaterialType.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairMaterialType.java
deleted file mode 100644
index 950871846..000000000
--- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairMaterialType.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.gmail.nossr50.skills.repair.repairables;
-
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-
-import com.gmail.nossr50.util.Permissions;
-
-public enum RepairMaterialType {
-    STRING,
-    LEATHER,
-    WOOD,
-    STONE,
-    IRON,
-    GOLD,
-    DIAMOND,
-    OTHER;
-
-    /**
-     * Get the base permissions associated with this RepairMaterialType.
-     *
-     * @param player The player to check the permissions for
-     *
-     * @return true if the player has permissions, false otherwise
-     */
-    public boolean getPermissions(Player player) {
-        switch (this) {
-            case STRING:
-                return Permissions.repairString(player);
-
-            case LEATHER:
-                return Permissions.repairLeather(player);
-
-            case WOOD:
-                return Permissions.repairWood(player);
-
-            case STONE:
-                return Permissions.repairStone(player);
-
-            case IRON:
-                return Permissions.repairIron(player);
-
-            case GOLD:
-                return Permissions.repairGold(player);
-
-            case DIAMOND:
-                return Permissions.repairDiamond(player);
-
-            case OTHER:
-                return Permissions.repairOtherMaterials(player);
-
-            default:
-                return false;
-        }
-    }
-
-    public Material getDefaultRepairMaterial() {
-        switch (this) {
-            case STRING:
-                return Material.STRING;
-
-            case LEATHER:
-                return Material.LEATHER;
-
-            case WOOD:
-                return Material.WOOD;
-
-            case STONE:
-                return Material.COBBLESTONE;
-
-            case IRON:
-                return Material.IRON_INGOT;
-
-            case GOLD:
-                return Material.GOLD_INGOT;
-
-            case DIAMOND:
-                return Material.DIAMOND;
-
-            case OTHER:
-            default:
-                return null;
-        }
-    }
-}
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java
index c86535c87..914e0f70f 100644
--- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java
+++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java
@@ -2,6 +2,9 @@ package com.gmail.nossr50.skills.repair.repairables;
 
 import org.bukkit.Material;
 
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
 
 public interface Repairable {
     /**
@@ -30,14 +33,14 @@ public interface Repairable {
      *
      * @return the RepairItemType for this repairable
      */
-    public RepairItemType getRepairItemType();
+    public ItemType getRepairItemType();
 
     /**
      * Gets the RepairMaterialType value for this repairable item
      *
      * @return the RepairMaterialType for this repairable
      */
-    public RepairMaterialType getRepairMaterialType();
+    public MaterialType getRepairMaterialType();
 
     /**
      * Gets the minimum quantity of repair materials ignoring all other repair bonuses
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java
index 588b58bb7..9e1e19b9b 100644
--- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java
+++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableFactory.java
@@ -2,13 +2,16 @@ package com.gmail.nossr50.skills.repair.repairables;
 
 import org.bukkit.Material;
 
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
 
 public class RepairableFactory {
     public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, byte repairMetadata, int minimumQuantity, short maximumDurability) {
-        return getRepairable(itemMaterial, repairMaterial, repairMetadata, 0, minimumQuantity, maximumDurability, RepairItemType.OTHER, RepairMaterialType.OTHER, 1);
+        return getRepairable(itemMaterial, repairMaterial, repairMetadata, 0, minimumQuantity, maximumDurability, ItemType.OTHER, MaterialType.OTHER, 1);
     }
 
-    public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, byte repairMetadata, int minimumLevel, int minimumQuantity, short maximumDurability, RepairItemType repairItemType, RepairMaterialType repairMaterialType, double xpMultiplier) {
+    public static Repairable getRepairable(Material itemMaterial, Material repairMaterial, byte repairMetadata, int minimumLevel, int minimumQuantity, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) {
         // TODO: Add in loading from config what type of repairable we want.
         return new SimpleRepairable(itemMaterial, repairMaterial, repairMetadata, minimumLevel, minimumQuantity, maximumDurability, repairItemType, repairMaterialType, xpMultiplier);
     }
diff --git a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java
index a74a7c6c1..0efdf8ddd 100644
--- a/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java
+++ b/src/main/java/com/gmail/nossr50/skills/repair/repairables/SimpleRepairable.java
@@ -2,17 +2,20 @@ package com.gmail.nossr50.skills.repair.repairables;
 
 import org.bukkit.Material;
 
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
 
 public class SimpleRepairable implements Repairable {
     private final Material itemMaterial, repairMaterial;
     private final int minimumQuantity, minimumLevel;
     private final short maximumDurability, baseRepairDurability;
     private final byte repairMetadata;
-    private final RepairItemType repairItemType;
-    private final RepairMaterialType repairMaterialType;
+    private final ItemType repairItemType;
+    private final MaterialType repairMaterialType;
     private final double xpMultiplier;
 
-    protected SimpleRepairable(Material type, Material repairMaterial, byte repairMetadata, int minimumLevel, int minimumQuantity, short maximumDurability, RepairItemType repairItemType, RepairMaterialType repairMaterialType, double xpMultiplier) {
+    protected SimpleRepairable(Material type, Material repairMaterial, byte repairMetadata, int minimumLevel, int minimumQuantity, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) {
         this.itemMaterial = type;
         this.repairMaterial = repairMaterial;
         this.repairMetadata = repairMetadata;
@@ -41,12 +44,12 @@ public class SimpleRepairable implements Repairable {
     }
 
     @Override
-    public RepairItemType getRepairItemType() {
+    public ItemType getRepairItemType() {
         return repairItemType;
     }
 
     @Override
-    public RepairMaterialType getRepairMaterialType() {
+    public MaterialType getRepairMaterialType() {
         return repairMaterialType;
     }
 
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java
index b1cf4bb99..3f6c3807e 100644
--- a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java
@@ -1,12 +1,9 @@
 package com.gmail.nossr50.skills.salvage;
 
 import org.bukkit.Material;
-import org.bukkit.inventory.ItemStack;
 
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.util.ItemUtils;
-import com.gmail.nossr50.util.skills.SkillUtils;
 
 public class Salvage {
     // The order of the values is extremely important, a few methods depend on it to work properly
@@ -53,58 +50,8 @@ public class Salvage {
     public static boolean arcaneSalvageDowngrades  = AdvancedConfig.getInstance().getArcaneSalvageEnchantDowngradeEnabled();
     public static boolean arcaneSalvageEnchantLoss = AdvancedConfig.getInstance().getArcaneSalvageEnchantLossEnabled();
 
-    /**
-     * Checks if the item is salvageable.
-     *
-     * @param item Item to check
-     *
-     * @return true if the item is salvageable, false otherwise
-     */
-    public static boolean isSalvageable(ItemStack item) {
-        if (Config.getInstance().getSalvageTools() && ItemUtils.isMinecraftTool(item)) {
-            return true;
-        }
-
-        if (Config.getInstance().getSalvageArmor() && !ItemUtils.isChainmailArmor(item) && ItemUtils.isMinecraftArmor(item)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    protected static Material getSalvagedItem(ItemStack inHand) {
-        if (ItemUtils.isDiamondTool(inHand) || ItemUtils.isDiamondArmor(inHand)) {
-            return Material.DIAMOND;
-        }
-        else if (ItemUtils.isGoldTool(inHand) || ItemUtils.isGoldArmor(inHand)) {
-            return Material.GOLD_INGOT;
-        }
-        else if (ItemUtils.isIronTool(inHand) || ItemUtils.isIronArmor(inHand)) {
-            return Material.IRON_INGOT;
-        }
-        else if (ItemUtils.isStoneTool(inHand)) {
-            return Material.COBBLESTONE;
-        }
-        else if (ItemUtils.isWoodTool(inHand)) {
-            return Material.WOOD;
-        }
-        else if (ItemUtils.isLeatherArmor(inHand)) {
-            return Material.LEATHER;
-        }
-        else if (ItemUtils.isStringTool(inHand)) {
-            return Material.STRING;
-        }
-        else {
-            return null;
-        }
-    }
-
-    protected static int getSalvagedAmount(ItemStack inHand) {
-        return SkillUtils.getRepairAndSalvageQuantities(inHand, getSalvagedItem(inHand), (byte) -1);
-    }
-
     protected static int calculateSalvageableAmount(short currentDurability, short maxDurability, int baseAmount) {
-        double percentDamaged = (double) (maxDurability - currentDurability) / maxDurability;
+        double percentDamaged = (maxDurability <= 0) ? 1D : (double) (maxDurability - currentDurability) / maxDurability;
 
         return (int) Math.floor(baseAmount * percentDamaged);
     }
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java
index 77e2c52ac..066acad88 100644
--- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java
@@ -11,14 +11,20 @@ import org.bukkit.enchantments.Enchantment;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.EnchantmentStorageMeta;
+import org.bukkit.material.MaterialData;
 
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.SkillManager;
 import com.gmail.nossr50.skills.salvage.Salvage.Tier;
+import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
 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 SalvageManager extends SkillManager {
     private boolean placedAnvil;
@@ -30,20 +36,23 @@ public class SalvageManager extends SkillManager {
 
     /**
      * Handles notifications for placing an anvil.
-     *
-     * @param anvilType The {@link Material} of the anvil block
      */
-    public void placedAnvilCheck(Material anvilType) {
+    public void placedAnvilCheck() {
         Player player = getPlayer();
 
-        if (getPlacedAnvil(anvilType)) {
+        if (getPlacedAnvil()) {
             return;
         }
 
-        player.sendMessage(LocaleLoader.getString("Salvage.Listener.Anvil"));
+        if (Config.getInstance().getSalvageAnvilMessagesEnabled()) {
+            player.sendMessage(LocaleLoader.getString("Salvage.Listener.Anvil"));
+        }
 
-        player.playSound(player.getLocation(), Sound.ANVIL_LAND, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
-        togglePlacedAnvil(anvilType);
+        if (Config.getInstance().getSalvageAnvilPlaceSoundsEnabled()) {
+            player.playSound(player.getLocation(), Sound.ANVIL_LAND, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
+        }
+
+        togglePlacedAnvil();
     }
 
     public void handleSalvage(Location location, ItemStack item) {
@@ -53,20 +62,43 @@ public class SalvageManager extends SkillManager {
             return;
         }
 
-        if (item.getDurability() != 0 && (getSkillLevel() < Salvage.advancedSalvageUnlockLevel || !Permissions.advancedSalvage(player))) {
-            player.sendMessage(LocaleLoader.getString("Salvage.Skills.AdeptDamaged"));
+        Salvageable salvageable = mcMMO.getSalvageableManager().getSalvageable(item.getType());
+
+        // Permissions checks on material and item types
+        if (!Permissions.salvageItemType(player, salvageable.getSalvageItemType())) {
+            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
             return;
         }
 
-        int salvageableAmount = Salvage.calculateSalvageableAmount(item.getDurability(), item.getType().getMaxDurability(), Salvage.getSalvagedAmount(item));
+        if (!Permissions.salvageMaterialType(player, salvageable.getSalvageMaterialType())) {
+            player.sendMessage(LocaleLoader.getString("mcMMO.NoPermission"));
+            return;
+        }
+
+        int skillLevel = getSkillLevel();
+        int minimumSalvageableLevel = salvageable.getMinimumLevel();
+
+        // Level check
+        if (skillLevel < minimumSalvageableLevel) {
+            player.sendMessage(LocaleLoader.getString("Salvage.Skills.Adept.Level", minimumSalvageableLevel, StringUtils.getPrettyItemString(item.getType())));
+            return;
+        }
+
+        if (item.getDurability() != 0 && (getSkillLevel() < Salvage.advancedSalvageUnlockLevel || !Permissions.advancedSalvage(player))) {
+            player.sendMessage(LocaleLoader.getString("Salvage.Skills.Adept.Damaged"));
+            return;
+        }
+
+        byte salvageMaterialMetadata = salvageable.getSalvageMaterialMetadata();
+
+        int salvageableAmount = Salvage.calculateSalvageableAmount(item.getDurability(), salvageable.getMaximumDurability(), salvageable.getMaximumQuantity());
 
         if (salvageableAmount == 0) {
             player.sendMessage(LocaleLoader.getString("Salvage.Skills.TooDamaged"));
             return;
         }
 
-        double salvagePercentage = Math.min((((Salvage.salvageMaxPercentage / Salvage.salvageMaxPercentageLevel) * getSkillLevel()) / 100.0D), Salvage.salvageMaxPercentage / 100.0D);
-        salvageableAmount = Math.max((int) (salvageableAmount * salvagePercentage), 1); // Always get at least something back, if you're capable of repairing it.
+        salvageableAmount = Math.max((int) (salvageableAmount * getMaxSalvagePercentage()), 1); // Always get at least something back, if you're capable of salvaging it.
 
         player.setItemInHand(new ItemStack(Material.AIR));
         location.add(0, 1, 0);
@@ -81,10 +113,19 @@ public class SalvageManager extends SkillManager {
             }
         }
 
-        Misc.dropItems(location, new ItemStack(Salvage.getSalvagedItem(item)), salvageableAmount);
+        Misc.dropItems(location, new MaterialData(salvageable.getSalvageMaterial(), salvageMaterialMetadata).toItemStack(salvageableAmount), 1);
 
-        player.playSound(player.getLocation(), Sound.ANVIL_USE, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
-        player.sendMessage(LocaleLoader.getString("Repair.Skills.SalvageSuccess"));
+        // BWONG BWONG BWONG - CLUNK!
+        if (Config.getInstance().getSalvageAnvilUseSoundsEnabled()) {
+            player.playSound(player.getLocation(), Sound.ANVIL_USE, Misc.ANVIL_USE_VOLUME, Misc.ANVIL_USE_PITCH);
+            player.playSound(player.getLocation(), Sound.ITEM_BREAK, 1.0F, 1.0F);
+        }
+
+        player.sendMessage(LocaleLoader.getString("Salvage.Skills.Success"));
+    }
+
+    public double getMaxSalvagePercentage() {
+        return Math.min((((Salvage.salvageMaxPercentage / Salvage.salvageMaxPercentageLevel) * getSkillLevel()) / 100.0D), Salvage.salvageMaxPercentage / 100.0D);
     }
 
     /**
@@ -174,45 +215,56 @@ public class SalvageManager extends SkillManager {
         return book;
     }
 
+    /**
+     * Check if the player has tried to use an Anvil before.
+     * @param actualize
+     *
+     * @return true if the player has confirmed using an Anvil
+     */
+    public boolean checkConfirmation(boolean actualize) {
+        Player player = getPlayer();
+        long lastUse = getLastAnvilUse();
+
+        if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getSalvageConfirmRequired()) {
+            return true;
+        }
+
+        if (!actualize) {
+            return false;
+        }
+
+        actualizeLastAnvilUse();
+
+        player.sendMessage(LocaleLoader.getString("Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name")));
+
+        return false;
+    }
+
     /*
      * Salvage Anvil Placement
      */
 
-    public boolean getPlacedAnvil(Material anvilType) {
-        if (anvilType == Salvage.anvilMaterial) {
-            return placedAnvil;
-        }
-
-        return true;
+    public boolean getPlacedAnvil() {
+        return placedAnvil;
     }
 
-    public void togglePlacedAnvil(Material anvilType) {
-        if (anvilType == Salvage.anvilMaterial) {
-            placedAnvil = !placedAnvil;
-        }
+    public void togglePlacedAnvil() {
+        placedAnvil = !placedAnvil;
     }
 
     /*
      * Salvage Anvil Usage
      */
 
-    public int getLastAnvilUse(Material anvilType) {
-        if (anvilType == Salvage.anvilMaterial) {
-            return lastClick;
-        }
-
-        return 0;
+    public int getLastAnvilUse() {
+        return lastClick;
     }
 
-    public void setLastAnvilUse(Material anvilType, int value) {
-        if (anvilType == Salvage.anvilMaterial) {
-            lastClick = value;
-        }
+    public void setLastAnvilUse(int value) {
+        lastClick = value;
     }
 
-    public void actualizeLastAnvilUse(Material anvilType) {
-        if (anvilType == Salvage.anvilMaterial) {
-            lastClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
-        }
+    public void actualizeLastAnvilUse() {
+        lastClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR);
     }
 }
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java
new file mode 100644
index 000000000..0f6f4a160
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/Salvageable.java
@@ -0,0 +1,82 @@
+package com.gmail.nossr50.skills.salvage.salvageables;
+
+import org.bukkit.Material;
+
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
+public interface Salvageable {
+    /**
+     * Gets the type of this repairable item
+     *
+     * @return the type of this repairable
+     */
+    public Material getItemMaterial();
+
+    /**
+     * Gets the id of the material used to repair this item
+     *
+     * @return the id of the repair material
+     */
+    public Material getSalvageMaterial();
+
+    /**
+     * Gets the metadata byte value of the material used to repair this item
+     *
+     * @return the byte metadata of the repair material
+     */
+    public byte getSalvageMaterialMetadata();
+
+    /**
+     * Gets the RepairItemType value for this repairable item
+     *
+     * @return the RepairItemType for this repairable
+     */
+    public ItemType getSalvageItemType();
+
+    /**
+     * Gets the RepairMaterialType value for this repairable item
+     *
+     * @return the RepairMaterialType for this repairable
+     */
+    public MaterialType getSalvageMaterialType();
+
+    /**
+     * Gets the maximum quantity of salvage materials ignoring all other salvage bonuses
+     *
+     * This is typically set to the number of items needed to create that item, for example 5 for helmets or 2 for swords
+     *
+     * @return the maximum number of items
+     */
+    public int getMaximumQuantity();
+
+    /**
+     * Gets the maximum durability of this item before it breaks
+     *
+     * @return the maximum durability
+     */
+    public short getMaximumDurability();
+
+    /**
+     * Gets the base repair durability on which to calculate bonuses.
+     *
+     * This is actually the maximum durability divided by the minimum quantity
+     *
+     * @return the base repair durability
+     */
+    public short getBaseSalvageDurability();
+
+    /**
+     * Gets the minimum repair level needed to repair this item
+     *
+     * @return the minimum level to repair this item, or 0 for no minimum
+     */
+    public int getMinimumLevel();
+
+    /**
+     * Gets the xpMultiplier for this repairable
+     *
+     * @return the xpMultiplier of this repairable
+     */
+    public double getXpMultiplier();
+}
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java
new file mode 100644
index 000000000..f59e62de6
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableFactory.java
@@ -0,0 +1,17 @@
+package com.gmail.nossr50.skills.salvage.salvageables;
+
+import org.bukkit.Material;
+
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
+public class SalvageableFactory {
+    public static Salvageable getSalvageable(Material itemMaterial, Material repairMaterial, byte repairMetadata, int maximumQuantity, short maximumDurability) {
+        return getSalvageable(itemMaterial, repairMaterial, repairMetadata, 0, maximumQuantity, maximumDurability, ItemType.OTHER, MaterialType.OTHER, 1);
+    }
+
+    public static Salvageable getSalvageable(Material itemMaterial, Material repairMaterial, byte repairMetadata, int minimumLevel, int maximumQuantity, short maximumDurability, ItemType repairItemType, MaterialType repairMaterialType, double xpMultiplier) {
+        // TODO: Add in loading from config what type of repairable we want.
+        return new SimpleSalvageable(itemMaterial, repairMaterial, repairMetadata, minimumLevel, maximumQuantity, maximumDurability, repairItemType, repairMaterialType, xpMultiplier);
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java
new file mode 100644
index 000000000..5da0b91fe
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SalvageableManager.java
@@ -0,0 +1,49 @@
+package com.gmail.nossr50.skills.salvage.salvageables;
+
+import java.util.List;
+
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+
+public interface SalvageableManager {
+    /**
+     * Register a salvageable with the SalvageManager
+     *
+     * @param salvageable Salvageable to register
+     */
+    public void registerSalvageable(Salvageable salvageable);
+
+    /**
+     * Register a list of salvageables with the SalvageManager
+     *
+     * @param salvageables List<Salvageable> to register
+     */
+    public void registerSalvageables(List<Salvageable> salvageables);
+
+    /**
+     * Checks if an item is salvageable
+     *
+     * @param type Material to check if salvageable
+     *
+     * @return true if salvageable, false if not
+     */
+    public boolean isSalvageable(Material type);
+
+    /**
+     * Checks if an item is salvageable
+     *
+     * @param itemStack Item to check if salvageable
+     *
+     * @return true if salvageable, false if not
+     */
+    public boolean isSalvageable(ItemStack itemStack);
+
+    /**
+     * Gets the salvageable with this type
+     *
+     * @param type Material of the salvageable to look for
+     *
+     * @return the salvageable, can be null
+     */
+    public Salvageable getSalvageable(Material type);
+}
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java
new file mode 100644
index 000000000..98615a4c4
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageable.java
@@ -0,0 +1,80 @@
+package com.gmail.nossr50.skills.salvage.salvageables;
+
+import org.bukkit.Material;
+
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
+
+
+public class SimpleSalvageable implements Salvageable {
+    private final Material itemMaterial, salvageMaterial;
+    private final int maximumQuantity, minimumLevel;
+    private final short maximumDurability, baseSalvageDurability;
+    private final byte salvageMetadata;
+    private final ItemType salvageItemType;
+    private final MaterialType salvageMaterialType;
+    private final double xpMultiplier;
+
+    protected SimpleSalvageable(Material type, Material salvageMaterial, byte salvageMetadata, int minimumLevel, int maximumQuantity, short maximumDurability, ItemType salvageItemType, MaterialType salvageMaterialType, double xpMultiplier) {
+        this.itemMaterial = type;
+        this.salvageMaterial = salvageMaterial;
+        this.salvageMetadata = salvageMetadata;
+        this.salvageItemType = salvageItemType;
+        this.salvageMaterialType = salvageMaterialType;
+        this.minimumLevel = minimumLevel;
+        this.maximumQuantity = maximumQuantity;
+        this.maximumDurability = maximumDurability;
+        this.baseSalvageDurability = (short) (maximumDurability / maximumQuantity);
+        this.xpMultiplier = xpMultiplier;
+    }
+
+    @Override
+    public Material getItemMaterial() {
+        return itemMaterial;
+    }
+
+    @Override
+    public Material getSalvageMaterial() {
+        return salvageMaterial;
+    }
+
+    @Override
+    public byte getSalvageMaterialMetadata() {
+        return salvageMetadata;
+    }
+
+    @Override
+    public ItemType getSalvageItemType() {
+        return salvageItemType;
+    }
+
+    @Override
+    public MaterialType getSalvageMaterialType() {
+        return salvageMaterialType;
+    }
+
+    @Override
+    public int getMaximumQuantity() {
+        return maximumQuantity;
+    }
+
+    @Override
+    public short getMaximumDurability() {
+        return maximumDurability;
+    }
+
+    @Override
+    public short getBaseSalvageDurability() {
+        return baseSalvageDurability;
+    }
+
+    @Override
+    public int getMinimumLevel() {
+        return minimumLevel;
+    }
+
+    @Override
+    public double getXpMultiplier() {
+        return xpMultiplier;
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java
new file mode 100644
index 000000000..847bdd69c
--- /dev/null
+++ b/src/main/java/com/gmail/nossr50/skills/salvage/salvageables/SimpleSalvageableManager.java
@@ -0,0 +1,48 @@
+package com.gmail.nossr50.skills.salvage.salvageables;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+
+
+public class SimpleSalvageableManager implements SalvageableManager {
+    private HashMap<Material, Salvageable> salvageables;
+
+    public SimpleSalvageableManager() {
+        this(55);
+    }
+
+    public SimpleSalvageableManager(int salvageablesSize) {
+        this.salvageables = new HashMap<Material, Salvageable>(salvageablesSize);
+    }
+
+    @Override
+    public void registerSalvageable(Salvageable salvageable) {
+        Material item = salvageable.getItemMaterial();
+        salvageables.put(item, salvageable);
+    }
+
+    @Override
+    public void registerSalvageables(List<Salvageable> salvageables) {
+        for (Salvageable salvageable : salvageables) {
+            registerSalvageable(salvageable);
+        }
+    }
+
+    @Override
+    public boolean isSalvageable(Material type) {
+        return salvageables.containsKey(type);
+    }
+
+    @Override
+    public boolean isSalvageable(ItemStack itemStack) {
+        return isSalvageable(itemStack.getType());
+    }
+
+    @Override
+    public Salvageable getSalvageable(Material type) {
+        return salvageables.get(type);
+    }
+}
diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java
index 0b2b09294..d46d94f1c 100644
--- a/src/main/java/com/gmail/nossr50/util/Permissions.java
+++ b/src/main/java/com/gmail/nossr50/util/Permissions.java
@@ -11,6 +11,8 @@ import org.bukkit.plugin.PluginManager;
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.commands.party.PartySubcommandType;
+import com.gmail.nossr50.datatypes.skills.ItemType;
+import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.skills.SecondaryAbility;
 import com.gmail.nossr50.datatypes.skills.SkillType;
 
@@ -162,24 +164,16 @@ public final class Permissions {
     public static boolean superBreaker(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.mining.superbreaker"); }
 
     /* REPAIR */
-
-    public static boolean repairArmor(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.armorrepair"); }
-    public static boolean repairTools(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.toolrepair"); }
-    public static boolean repairOtherItems(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.otherrepair"); }
-
-    public static boolean repairDiamond(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.diamondrepair"); }
-    public static boolean repairGold(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.goldrepair"); }
-    public static boolean repairIron(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.ironrepair"); }
-    public static boolean repairLeather(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.leatherrepair"); }
-    public static boolean repairOtherMaterials(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.othermaterialrepair"); }
-    public static boolean repairString(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.stringrepair"); }
-    public static boolean repairStone(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.stonerepair"); }
-    public static boolean repairWood(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.repair.woodrepair"); }
+    public static boolean repairItemType(Permissible permissible, ItemType repairItemType) { return permissible.hasPermission("mcmmo.ability.repair." + repairItemType.toString().toLowerCase() + "repair"); }
+    public static boolean repairMaterialType(Permissible permissible, MaterialType repairMaterialType) { return permissible.hasPermission("mcmmo.ability.repair." + repairMaterialType.toString().toLowerCase() + "repair"); }
 
     /* SALVAGE */
     public static boolean advancedSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.advancedsalvage"); }
     public static boolean arcaneSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.arcanesalvage"); }
 
+    public static boolean salvageItemType(Permissible permissible, ItemType salvageItemType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageItemType.toString().toLowerCase() + "salvage"); }
+    public static boolean salvageMaterialType(Permissible permissible, MaterialType salvageMaterialType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageMaterialType.toString().toLowerCase() + "salvage"); }
+
     /* SMELTING */
     public static boolean fluxMining(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.smelting.fluxmining"); }
     public static boolean fuelEfficiency(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.smelting.fuelefficiency"); }
diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
index c8dde01b7..dcc98940a 100644
--- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
+++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
@@ -256,25 +256,31 @@ public class SkillUtils {
     }
 
     public static int getRepairAndSalvageQuantities(ItemStack item, Material repairMaterial, byte repairMetadata) {
+        // Workaround for Bukkit bug where damaged items would not return any recipes
+        item = item.clone();
+        item.setDurability((short) 0);
+
         int quantity = 0;
         MaterialData repairData = repairMaterial != null ? new MaterialData(repairMaterial, repairMetadata) : null;
         List<Recipe> recipes = mcMMO.p.getServer().getRecipesFor(item);
 
-        if (!recipes.isEmpty()) {
-            Recipe recipe = recipes.get(0);
+        if (recipes.isEmpty()) {
+            return quantity;
+        }
 
-            if (recipe instanceof ShapelessRecipe) {
-                for (ItemStack ingredient : ((ShapelessRecipe) recipe).getIngredientList()) {
-                    if (ingredient != null && (repairMaterial == null || ingredient.getType() == repairMaterial) && (repairMetadata == -1 || ingredient.getData().equals(repairData))) {
-                        quantity += ingredient.getAmount();
-                    }
+        Recipe recipe = recipes.get(0);
+
+        if (recipe instanceof ShapelessRecipe) {
+            for (ItemStack ingredient : ((ShapelessRecipe) recipe).getIngredientList()) {
+                if (ingredient != null && (repairMaterial == null || ingredient.getType() == repairMaterial) && (repairMetadata == -1 || ingredient.getData().equals(repairData))) {
+                    quantity += ingredient.getAmount();
                 }
             }
-            else if (recipe instanceof ShapedRecipe) {
-                for (ItemStack ingredient : ((ShapedRecipe) recipe).getIngredientMap().values()) {
-                    if (ingredient != null && (repairMaterial == null || ingredient.getType() == repairMaterial) && (repairMetadata == -1 || ingredient.getData().equals(repairData))) {
-                        quantity += ingredient.getAmount();
-                    }
+        }
+        else if (recipe instanceof ShapedRecipe) {
+            for (ItemStack ingredient : ((ShapedRecipe) recipe).getIngredientMap().values()) {
+                if (ingredient != null && (repairMaterial == null || ingredient.getType() == repairMaterial) && (repairMetadata == -1 || ingredient.getData().equals(repairData))) {
+                    quantity += ingredient.getAmount();
                 }
             }
         }
diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml
index e59222297..3eb8e9859 100644
--- a/src/main/resources/advanced.yml
+++ b/src/main/resources/advanced.yml
@@ -314,10 +314,6 @@ Skills:
             ChanceMax: 100.0
             MaxBonusLevel: 1000
 
-        Salvage:
-            # UnlockLevel: Level when Salvage become available
-            UnlockLevel: 600
-
         ArcaneForging:
             May_Lose_Enchants: true
             Rank_Levels:
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 84570a1d7..9fe78c6f4 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -313,9 +313,11 @@ Skills:
     Salvage:
         Level_Cap: 0
         Anvil_Messages: true
-        Salvage_Anvil_Material: GOLD_BLOCK
-        Salvage_tools: true
-        Salvage_armor: true
+        Anvil_Placed_Sounds: true
+        Anvil_Use_Sounds: true
+        Anvil_Material: GOLD_BLOCK
+        # Ask for a confirmation when a player tries to salvage an enchanted item
+        Confirm_Required: true
     Smelting:
         Level_Cap: 0
     Swords:
diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties
index ab62a24a4..a3a1057cf 100644
--- a/src/main/resources/locale/locale_en_US.properties
+++ b/src/main/resources/locale/locale_en_US.properties
@@ -269,15 +269,17 @@ Salvage.Effect.2=Arcane Salvaging
 Salvage.Effect.3=Extract enchantments from items
 Salvage.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (ADVANCED SALVAGE)
 Salvage.Ability.Bonus.0=Advanced Salvage
-Salvage.Ability.Bonus.1=Salvaging damaged items will grant you items accordingly
+Salvage.Ability.Bonus.1=Max yield {0} item destroyed
 Salvage.Arcane.Rank=[[RED]]Arcane Salvaging: [[YELLOW]]Rank {0}/{1}
 Salvage.Arcane.ExtractFull=[[GRAY]]AS Full-Enchant Chance
 Salvage.Arcane.ExtractPartial=[[GRAY]]AS Partial-Enchant Chance
-Salvage.Skills.AdeptDamaged=You aren't skilled enough to salvage damaged items.
-Salvage.Skills.TooDamaged=This item is too damaged to be salvaged.
-Salvage.Skills.ArcaneFailed=You were unable to extract the knowledge contained within this item.
-Salvage.Skills.ArcanePartial=You were only able to extract some of the knowledge contained within this item.
-Salvage.Skills.ArcaneSuccess=You able to extract all of the knowledge contained within this item!
+Salvage.Skills.Success=[[GREEN]]Item salvaged!
+Salvage.Skills.Adept.Damaged=[[DARK_RED]]You aren't skilled enough to salvage damaged items.
+Salvage.Skills.Adept.Level=[[RED]]You must be level [[YELLOW]]{0}[[RED]] to salvage [[YELLOW]]{1}
+Salvage.Skills.TooDamaged=[[DARK_RED]]This item is too damaged to be salvaged.
+Salvage.Skills.ArcaneFailed=[[RED]]You were unable to extract the knowledge contained within this item.
+Salvage.Skills.ArcanePartial=[[YELLOW]]You were only able to extract some of the knowledge contained within this item.
+Salvage.Skills.ArcaneSuccess=[[GREEN]]You able to extract all of the knowledge contained within this item!
 Salvage.Listener.Anvil=[[DARK_RED]]You have placed a Salvage anvil, use this to Salvage tools and armor.
 Salvage.Listener=Salvage:
 Salvage.SkillName=SALVAGE
@@ -772,12 +774,21 @@ Guides.Mining.Section.4=[[DARK_AQUA]]How to use Blast Mining:\n[[YELLOW]]With a
 Guides.Mining.Section.5=[[DARK_AQUA]]How does Blast Mining work?\n[[YELLOW]]Blast Mining is an ability with a cooldown tied to the Mining\n[[YELLOW]]skill. It gives bonuses when mining with TNT and allows you\n[[YELLOW]]to remote detonate TNT. There are three parts to Blast Mining.\n[[YELLOW]]The first part is Bigger Bombs, which increases blast radius.\n[[YELLOW]]The second is Demolitions Expert, which decreases damage\n[[YELLOW]]from TNT explosions. The third part simply increases the\n[[YELLOW]]amount of ores dropped from TNT and decreases the\n[[YELLOW]]debris dropped.
 
 ##Repair
-Guides.Repair.Section.0=[[DARK_AQUA]]About Repair:\n[[YELLOW]]Repair allows you to use an iron block to repair armor and\n[[YELLOW]]tools, or a gold block to salvage armor and tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Repair tools or armor using the mcMMO Anvil. This is an\n[[YELLOW]]iron block by default and should not be confused with\n[[YELLOW]]the Vanilla Minecraft Anvil.
+Guides.Repair.Section.0=[[DARK_AQUA]]About Repair:\n[[YELLOW]]Repair allows you to use an iron block to repair armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Repair tools or armor using the mcMMO Anvil. This is an\n[[YELLOW]]iron block by default and should not be confused with\n[[YELLOW]]the Vanilla Minecraft Anvil.
 Guides.Repair.Section.1=[[DARK_AQUA]]How can I use Repair?\n[[YELLOW]]Place down a mcMMO Anvil and right-click to repair the item \n[[YELLOW]]you're currently holding. This consumes 1 item on every use.
 Guides.Repair.Section.2=[[DARK_AQUA]]How does Repair Mastery work?\n[[YELLOW]]Repair Mastery increases the repair amount. The extra amount\n[[YELLOW]]repaired is influenced by your Repair skill level.
 Guides.Repair.Section.3=[[DARK_AQUA]]How does Super Repair work?\n[[YELLOW]]Super Repair is a passive ability. When repairing an item,\n[[YELLOW]]it grants players a chance to repair an item with\n[[YELLOW]]double effectiveness.
 Guides.Repair.Section.4=[[DARK_AQUA]]How does Arcane Forging work?\n[[YELLOW]]This passive ability allows you to repair items with a certain\n[[YELLOW]]chance of maintaining its enchantments. The enchants may be\n[[YELLOW]]kept at their existing levels, downgraded to a lower level,\n[[YELLOW]]or lost entirely.
-Guides.Repair.Section.5=[[DARK_AQUA]]How does Salvage work?\n[[YELLOW]]Place down a mcMMO Salvage Anvil and right-click to salvage\n[[YELLOW]]the item you're currently holding.\n[[YELLOW]]This will break the item apart en give back the used ingots.\n[[YELLOW]]Note: You can only salvage fully repaired tools or armor.
+
+##Salvage
+Guides.Salvage.Section.0=[[DARK_AQUA]]About Salvage:\n[[YELLOW]]Salvage allows you to use an gold block to salvage armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Salvage is a child skill of Repair and Fishing, your Salvage\n[[YELLOW]]skill level is based on your Fishing and Repair skill levels.
+Guides.Salvage.Section.1=[[DARK_AQUA]]How can I use Salvage?\n[[YELLOW]]Place down a mcMMO Salvage Anvil and right-click to salvage\n[[YELLOW]]the item you're currently holding. This will break apart the item,\n[[YELLOW]]and give back materials used to craft the item.\n\n[[YELLOW]]For example, salvaging an iron pickaxe will give you iron bars.
+Guides.Salvage.Section.2=[[DARK_AQUA]]How does Advanced Salvage work?\n[[YELLOW]]When unlocked, this ability allows you to salvage damaged items.\n[[YELLOW]]The yield percentage increases as you level up. A higher yield\n[[YELLOW]]means that you can get more materials back.\n[[YELLOW]]With advanced salvage you will always get 1 material back,\n[[YELLOW]]unless the item is too damaged. So you don't have to worry\n[[YELLOW]]about destroying items without getting anything in return.
+Guides.Salvage.Section.3=[[DARK_AQUA]]To illustrate how this works, here's an example:\n[[YELLOW]]Let's say we salvage a gold pickaxe which is damaged for 20%,\n[[YELLOW]]this means that the maximum amount you could get is only 2\n[[YELLOW]](because the pick is crafted with 3 ingots - each worth\n[[YELLOW]]33,33% durability) which is equal to 66%. If your yield\n[[YELLOW]]percentage is below 66% you are not able to get 2 ingots.\n[[YELLOW]]If it is above this value you are able to gain the "full amount",\n[[YELLOW]]which means that you will get 2 ingots.
+Guides.Salvage.Section.4=[[DARK_AQUA]]How does Arcane Salvage work?\n[[YELLOW]]This ability allows you to get enchanted books when salvaging\n[[YELLOW]]enchanted items. Depending on your level the chance of\n[[YELLOW]]successfully extracting a full or partial enchantment varies.\n\n[[YELLOW]]When an enchantment is partially extracted, the enchantment\n[[YELLOW]]book will have a lower level enchantment compared to what\n[[YELLOW]]it was on the item.
+
+##Smelting
+Guides.Smelting.Section.0=Coming soon...
 
 ##Swords
 Guides.Swords.Section.0=[[DARK_AQUA]]About Swords:\n[[YELLOW]]This skill awards combat bonuses to anyone fighting with a\n[[YELLOW]]sword.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained based on the amount of damage dealt to mobs or \n[[YELLOW]]other players when wielding a sword.
@@ -785,9 +796,6 @@ Guides.Swords.Section.1=[[DARK_AQUA]]How does Serrated Strikes work?\n[[YELLOW]]
 Guides.Swords.Section.2=[[DARK_AQUA]]How does Counter Attack work?\n[[YELLOW]]Counter Attack is an active ability. When blocking and taking\n[[YELLOW]]hits from mobs, you will have a chance to reflect 50% of \n[[YELLOW]]the damage that was taken.
 Guides.Swords.Section.3=[[DARK_AQUA]]How does Bleed work?\n[[YELLOW]]Bleed causes enemies to take damage every two seconds. The \n[[YELLOW]]target will bleed until the effect wears off, or death, \n[[YELLOW]]whichever comes first.\n[[YELLOW]]The duration of the bleed is increased by your sword skill.
 
-##Smelting
-Guides.Smelting.Section.0=Coming soon...
-
 ##Taming
 Guides.Taming.Section.0=[[DARK_AQUA]]About Taming:\n[[YELLOW]]Taming will give players various combat bonuses when using\n[[YELLOW]]tamed wolves.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you need to tame wolves/ocelots or\n[[YELLOW]]get into combat with your wolves.
 Guides.Taming.Section.1=[[DARK_AQUA]]How does Call of the Wild work?\n[[YELLOW]]Call of the Wild is an active ability that will allow you to summon\n[[YELLOW]]a wolf or an ocelot by your side. You can do this by\n[[YELLOW]]left-clicking while holding bones or fish.
diff --git a/src/main/resources/repair.vanilla.yml b/src/main/resources/repair.vanilla.yml
index 4f8c1f50a..a491f5660 100644
--- a/src/main/resources/repair.vanilla.yml
+++ b/src/main/resources/repair.vanilla.yml
@@ -210,4 +210,4 @@ Repairables:
         XpMultiplier: .5
     CARROT_STICK:
         MinimumLevel: 0
-        XpMultiplier: .5
\ No newline at end of file
+        XpMultiplier: .5
diff --git a/src/main/resources/salvage.vanilla.yml b/src/main/resources/salvage.vanilla.yml
new file mode 100644
index 000000000..fe1c76833
--- /dev/null
+++ b/src/main/resources/salvage.vanilla.yml
@@ -0,0 +1,213 @@
+#
+#  Salvage configuration
+#  Last updated on ${project.version}-b${BUILD_NUMBER}
+#
+# Any file named salvage.*.yml in the mcmmmo folder will be loaded as a salvage config
+# All salvage configs have a main section titled "Salvageables"
+# Afterwards, all sub-items are considered a Salvageable to be loaded. The names of each subitem should be the exact material name.
+# The bare minimum of a Salvageable is that it has a minimumLevel and XpMultiplier.
+#
+# ItemType: This is the type of item to be repaired, this is only important to permissions.
+## Valid values are ARMOR, TOOL, and OTHER.
+## This defaults to OTHER.
+#
+# MaterialType: This is the type of the material of the item to be salvaged, this is only important for permissions.
+## Valid values are STRING, LEATHER, WOOD, STONE, IRON, GOLD, DIAMOND, and OTHER
+## This defaults to OTHER.
+#
+# SalvageMaterial: This is the material name of the item used to salvage this item.
+## This is required to be set for non craftable items, if not set mcMMO checks the crafting recipe to see which items
+## should be dropped when salvaging the item.
+#
+# SalvageMaterialMetadata: This is the metadata of the item used to salvage this item.
+## A value of -1 means to ignore all metadata when repairing.
+## This defaults to -1
+#
+# MaximumDurability: This is the maximum durability of the item.
+#
+# MinimumLevel: This is the minimum repair level needed to salvage this item.
+## Valid values are => 0
+## This defaults to 0
+#
+# MaximumQuantity: This is the maximum number of items yield after salvaging the item, ignoring all other salvage bonuses.
+## This is typically the number of the salvage material needed to create a new item, for example for a sword it is 2, for an axe it is 3
+## This defaults to 2
+#
+# XpMultiplier: This is the amount to multiply the xp bonus by.
+## This defaults to 1
+#
+#
+# The following is the default salvage config that ships with mcMMO, it contains all vanilla items that are salvageable.
+#
+#
+###
+Salvageables:
+    #
+    # Wooden salvageables
+    ###
+    # Tools
+    WOOD_SWORD:
+        MinimumLevel: 0
+        XpMultiplier: .25
+    WOOD_SPADE:
+        MinimumLevel: 0
+        XpMultiplier: .16
+    WOOD_PICKAXE:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    WOOD_AXE:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    WOOD_HOE:
+        MinimumLevel: 0
+        XpMultiplier: .25
+    #
+    # Stone salvageables
+    ###
+    # Tools
+    STONE_SWORD:
+        MinimumLevel: 0
+        XpMultiplier: .25
+    STONE_SPADE:
+        MinimumLevel: 0
+        XpMultiplier: .16
+    STONE_PICKAXE:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    STONE_AXE:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    STONE_HOE:
+        MinimumLevel: 0
+        XpMultiplier: .25
+    #
+    # Iron salvageables
+    ###
+    # Tools
+    IRON_SWORD:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    IRON_SPADE:
+        MinimumLevel: 0
+        XpMultiplier: .3
+    IRON_PICKAXE:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    IRON_AXE:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    IRON_HOE:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    SHEARS:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    FLINT_AND_STEEL:
+        MinimumLevel: 0
+        XpMultiplier: .3
+    # Armor
+    IRON_HELMET:
+        MinimumLevel: 0
+        XpMultiplier: 2
+    IRON_CHESTPLATE:
+        MinimumLevel: 0
+        XpMultiplier: 2
+    IRON_LEGGINGS:
+        MinimumLevel: 0
+        XpMultiplier: 2
+    IRON_BOOTS:
+        MinimumLevel: 0
+        XpMultiplier: 2
+    #
+    # Gold salvageables
+    ###
+    # Tools
+    GOLD_SWORD:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    GOLD_SPADE:
+        MinimumLevel: 0
+        XpMultiplier: 2.6
+    GOLD_PICKAXE:
+        MinimumLevel: 0
+        XpMultiplier: 8
+    GOLD_AXE:
+        MinimumLevel: 0
+        XpMultiplier: 8
+    GOLD_HOE:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    # Armor
+    GOLD_HELMET:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    GOLD_CHESTPLATE:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    GOLD_LEGGINGS:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    GOLD_BOOTS:
+        MinimumLevel: 0
+        XpMultiplier: 4
+    #
+    # Diamond salvageables
+    ###
+    # Tools
+    DIAMOND_SWORD:
+        MinimumLevel: 50
+        XpMultiplier: .5
+    DIAMOND_SPADE:
+        MinimumLevel: 50
+        XpMultiplier: .3
+    DIAMOND_PICKAXE:
+        MinimumLevel: 50
+        XpMultiplier: 1
+    DIAMOND_AXE:
+        MinimumLevel: 50
+        XpMultiplier: 1
+    DIAMOND_HOE:
+        MinimumLevel: 50
+        XpMultiplier: .5
+    # Armor
+    DIAMOND_HELMET:
+        MinimumLevel: 50
+        XpMultiplier: 6
+    DIAMOND_CHESTPLATE:
+        MinimumLevel: 50
+        XpMultiplier: 6
+    DIAMOND_LEGGINGS:
+        MinimumLevel: 50
+        XpMultiplier: 6
+    DIAMOND_BOOTS:
+        MinimumLevel: 50
+        XpMultiplier: 6
+    #
+    # Leather salvageables
+    ###
+    # Armor
+    LEATHER_HELMET:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    LEATHER_CHESTPLATE:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    LEATHER_LEGGINGS:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    LEATHER_BOOTS:
+        MinimumLevel: 0
+        XpMultiplier: 1
+    #
+    # String salvageables
+    ###
+    # Tools
+    FISHING_ROD:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    BOW:
+        MinimumLevel: 0
+        XpMultiplier: .5
+    CARROT_STICK:
+        MinimumLevel: 0
+        XpMultiplier: .5