浏览代码

MAJOR PERMISSIONS UPDATE. PLEASE CHECK PLUGIN.YML FOR DETAILS.

GJ 13 年之前
父节点
当前提交
99e58039a2

+ 2 - 1
Changelog.txt

@@ -12,8 +12,9 @@ Version 2.0.00-dev
  + Added ability to summon Ocelots with Call of the Wild
  + Added offline user functionality to mmoedit
  + Added bookshelves to list of blocks that don't trigger abilities.
- + Added 'mcmmo.skills.repair.arcanebypass' permission node to bypass Arcane Repair and keep your enchantments
+ + Added 'mcmmo.repair.arcanebypass' permission node to bypass Arcane Repair and keep your enchantments
  + Added config option to disable Herbalism's instant wheat replanting
+ + Added LOTS of new permissions nodes. *CHECK PLUGIN.YML FOR UPDATES*
  = Fixed Green Terra not awarding Triple Drops
  = Fixed ClassCastException from Taming preventDamage checks
  = Fixed issue with Blast Mining not seeing TNT for detonation due to snow

+ 1 - 1
pom.xml

@@ -110,7 +110,7 @@
                 <checksumPolicy>fail</checksumPolicy>
             </snapshots> 
         	<id>spout-repo</id>
-        	<url>http://nexus.getspout.org/content/groups/public/</url>
+        	<url>http://nexus.spout.org/content/groups/public/</url>
         </repository>
     </repositories>
     <dependencies>

+ 40 - 42
src/main/java/com/gmail/nossr50/Combat.java

@@ -60,7 +60,7 @@ public class Combat {
             combatAbilityChecks(attacker);
 
             if (ItemChecks.isSword(itemInHand) && mcPermissions.getInstance().swords(attacker)) {
-                if (!mcBleedTimer.contains(target)) {
+                if (!mcBleedTimer.contains(target) && mcPermissions.getInstance().swordsBleed(attacker)) {
                     Swords.bleedCheck(attacker, target, plugin);
                 }
 
@@ -71,9 +71,17 @@ public class Combat {
                 startGainXp(attacker, PPa, target, SkillType.SWORDS, plugin);
             }
             else if (ItemChecks.isAxe(itemInHand) && mcPermissions.getInstance().axes(attacker)) {
-                Axes.axesBonus(attacker, event);
-                Axes.axeCriticalCheck(attacker, event);
-                Axes.impact(attacker, target, event);
+                if (mcPermissions.getInstance().axeBonus(attacker)) {
+                    Axes.axesBonus(attacker, event);
+                }
+
+                if (mcPermissions.getInstance().criticalHit(attacker)) {
+                    Axes.axeCriticalCheck(attacker, event);
+                }
+
+                if (mcPermissions.getInstance().impact(attacker)) {
+                    Axes.impact(attacker, target, event);
+                }
 
                 if (PPa.getSkullSplitterMode()) {
                     applyAbilityAoE(attacker, target, damage, plugin, SkillType.AXES);
@@ -82,33 +90,22 @@ public class Combat {
                 startGainXp(attacker, PPa, target, SkillType.AXES, plugin);
             }
             else if (itemInHand.getType().equals(Material.AIR) && mcPermissions.getInstance().unarmed(attacker)) {
-                Unarmed.unarmedBonus(PPa, event);
+                if (mcPermissions.getInstance().unarmedBonus(attacker)) {
+                    Unarmed.unarmedBonus(PPa, event);
+                }
 
-                if (PPa.getBerserkMode()) {
-                    event.setDamage(damage + (damage / 2));
+                if (PPa.getBerserkMode() && mcPermissions.getInstance().berserk(attacker)) {
+                    event.setDamage((int) (damage * 1.5));
                 }
 
-                if (targetType.equals(EntityType.PLAYER)) {
+                if (targetType.equals(EntityType.PLAYER) && mcPermissions.getInstance().disarm(attacker)) {
                     Unarmed.disarmProcCheck(PPa, (Player) target);
                 }
 
                 startGainXp(attacker, PPa, target, SkillType.UNARMED, plugin);
             }
-            else if (itemInHand.getType().equals(Material.BONE) && mcPermissions.getInstance().taming(attacker) && targetType.equals(EntityType.WOLF)) {
-                Wolf wolf = (Wolf) target;
-                String message = mcLocale.getString("Combat.BeastLore") + " ";
-                int health = wolf.getHealth();
-                event.setCancelled(true);
-
-                if (wolf.isTamed()) {
-                    message = message.concat(mcLocale.getString("Combat.BeastLoreOwner", new Object[] {Taming.getOwnerName(wolf)}) + " ");
-                    message = message.concat(mcLocale.getString("Combat.BeastLoreHealthWolfTamed", new Object[] {health}));
-                }
-                else {
-                    message = message.concat(mcLocale.getString("Combat.BeastLoreHealthWolf", new Object[] {health}));
-                }
-
-                attacker.sendMessage(message);
+            else if (itemInHand.getType().equals(Material.BONE) && mcPermissions.getInstance().beastLore(attacker)) {
+                Taming.beastLore(event, target, attacker);
             }
             break;
 
@@ -120,9 +117,18 @@ public class Combat {
                 PlayerProfile PPo = Users.getProfile(master);
 
                 if (mcPermissions.getInstance().taming(master)) {
-                    Taming.fastFoodService(PPo, wolf, event);
-                    Taming.sharpenedClaws(PPo, event);
-                    Taming.gore(PPo, event, master, plugin);
+                    if (mcPermissions.getInstance().fastFoodService(master)) {
+                        Taming.fastFoodService(PPo, wolf, event);
+                    }
+
+                    if (mcPermissions.getInstance().sharpenedclaws(master)) {
+                        Taming.sharpenedClaws(PPo, event);
+                    }
+
+                    if (mcPermissions.getInstance().gore(master)) {
+                        Taming.gore(PPo, event, master, plugin);
+                    }
+
                     startGainXp(master, PPo, target, SkillType.TAMING, plugin);
                 }
             }
@@ -174,22 +180,9 @@ public class Combat {
 
         if (target instanceof Player) {
             Player defender = (Player) target;
-            PlayerProfile PPd = Users.getProfile(defender);
-            boolean deflect = false;
 
             if (mcPermissions.getInstance().unarmed(defender) && defender.getItemInHand().getType().equals(Material.AIR)) {
-                if (PPd.getSkillLevel(SkillType.UNARMED) >= 1000 && (Math.random() * 1000 <= 500)) {
-                    deflect = true;
-                }
-                else if (Math.random() * 1000 <= (PPd.getSkillLevel(SkillType.UNARMED) / 2)) {
-                    deflect = true;
-                }
-
-                if (deflect) {
-                    event.setCancelled(true);
-                    defender.sendMessage(mcLocale.getString("Combat.ArrowDeflect"));
-                    return;
-                }
+                Unarmed.deflectCheck(defender, event);
             }
         }
 
@@ -199,8 +192,13 @@ public class Combat {
             int damage = event.getDamage();
 
             if (mcPermissions.getInstance().archery(attacker) && damage > 0) {
-                Archery.trackArrows(pluginx, target, PPa);
-                Archery.ignitionCheck(target, attacker);
+                if (mcPermissions.getInstance().trackArrows(attacker)) {
+                    Archery.trackArrows(pluginx, target, PPa);
+                }
+
+                if (mcPermissions.getInstance().ignition(attacker)) {
+                    Archery.ignitionCheck(target, attacker);
+                }
 
                 startGainXp(attacker, PPa, target, SkillType.ARCHERY, pluginx);
 

+ 8 - 8
src/main/java/com/gmail/nossr50/datatypes/AbilityType.java

@@ -227,31 +227,31 @@ public enum AbilityType {
     public boolean getPermissions(Player player) {
         switch (this) {
         case BERSERK:
-            return mcPermissions.getInstance().unarmedAbility(player);
+            return mcPermissions.getInstance().berserk(player);
 
         case BLAST_MINING:
             return mcPermissions.getInstance().blastMining(player);
 
         case GIGA_DRILL_BREAKER:
-            return mcPermissions.getInstance().excavationAbility(player);
+            return mcPermissions.getInstance().gigaDrillBreaker(player);
 
         case GREEN_TERRA:
-            return mcPermissions.getInstance().herbalismAbility(player);
+            return mcPermissions.getInstance().greenTerra(player);
 
         case LEAF_BLOWER:
-            return mcPermissions.getInstance().woodcutting(player);
+            return mcPermissions.getInstance().leafBlower(player);
 
         case SERRATED_STRIKES:
-            return mcPermissions.getInstance().swordsAbility(player);
+            return mcPermissions.getInstance().serratedStrikes(player);
 
         case SKULL_SPLIITER:
-            return mcPermissions.getInstance().axesAbility(player);
+            return mcPermissions.getInstance().skullSplitter(player);
 
         case SUPER_BREAKER:
-            return mcPermissions.getInstance().miningAbility(player);
+            return mcPermissions.getInstance().superBreaker(player);
 
         case TREE_FELLER:
-            return mcPermissions.getInstance().woodCuttingAbility(player);
+            return mcPermissions.getInstance().treeFeller(player);
 
         default:
             return false;

+ 7 - 7
src/main/java/com/gmail/nossr50/listeners/mcBlockListener.java

@@ -127,18 +127,18 @@ public class mcBlockListener implements Listener {
          * HERBALISM
          */
 
-        //Green Terra
-        if (PP.getHoePreparationMode() && mcPermissions.getInstance().herbalismAbility(player) && ((mat.equals(Material.CROPS) && block.getData() == CropState.RIPE.getData()) || Herbalism.canBeGreenTerra(mat))) {
+        /* Green Terra */
+        if (PP.getHoePreparationMode() && mcPermissions.getInstance().greenTerra(player) && ((mat.equals(Material.CROPS) && block.getData() == CropState.RIPE.getData()) || Herbalism.canBeGreenTerra(mat))) {
             Skills.abilityCheck(player, SkillType.HERBALISM);
         }
 
-        //Wheat && Triple drops
+        /* Triple drops */
         if (PP.getGreenTerraMode() && Herbalism.canBeGreenTerra(mat)) {
             Herbalism.herbalismProcCheck(block, player, event, plugin);
             Herbalism.herbalismProcCheck(block, player, event, plugin); //Called twice for triple drop functionality
         }
 
-        if (mcPermissions.getInstance().herbalism(player) && Herbalism.canBeGreenTerra(mat)) {
+        if (mcPermissions.getInstance().herbalismDoubleDrops(player) && Herbalism.canBeGreenTerra(mat)) {
             Herbalism.herbalismProcCheck(block, player, event, plugin);
         }
 
@@ -168,7 +168,7 @@ public class mcBlockListener implements Listener {
             }
         }
 
-        if (PP.getTreeFellerMode() && mcPermissions.getInstance().woodCuttingAbility(player)) {
+        if (PP.getTreeFellerMode() && mcPermissions.getInstance().treeFeller(player)) {
             WoodCutting.treeFeller(event);
         }
 
@@ -213,7 +213,7 @@ public class mcBlockListener implements Listener {
             if (PP.getHoePreparationMode() && (Herbalism.canBeGreenTerra(mat) || Herbalism.makeMossy(mat))) {
                 Skills.abilityCheck(player, SkillType.HERBALISM);
             }
-            else if (PP.getAxePreparationMode() && mat.equals(Material.LOG) && mcPermissions.getInstance().woodCuttingAbility(player)) {  //Why are we checking the permissions here?
+            else if (PP.getAxePreparationMode() && mat.equals(Material.LOG) && mcPermissions.getInstance().treeFeller(player)) {  //Why are we checking the permissions here?
                 Skills.abilityCheck(player, SkillType.WOODCUTTING);
             }
             else if (PP.getPickaxePreparationMode() && Mining.canBeSuperBroken(mat)) {
@@ -235,7 +235,7 @@ public class mcBlockListener implements Listener {
         /*
          * ABILITY TRIGGER CHECKS
          */
-        if (PP.getGreenTerraMode() && mcPermissions.getInstance().herbalismAbility(player) && Herbalism.makeMossy(mat)) {
+        if (PP.getGreenTerraMode() && mcPermissions.getInstance().greenTerra(player) && Herbalism.makeMossy(mat)) {
             Herbalism.greenTerra(player, block);
         }
         else if (PP.getGigaDrillBreakerMode() && Skills.triggerCheck(player, block, AbilityType.GIGA_DRILL_BREAKER)) {

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

@@ -113,7 +113,7 @@ public class mcEntityListener implements Listener {
                 if (cause == DamageCause.FALL && mcPermissions.getInstance().acrobatics(player)) {
                     Acrobatics.acrobaticsCheck(player, event);
                 }
-                else if (cause == DamageCause.BLOCK_EXPLOSION && mcPermissions.getInstance().blastMining(player)) {
+                else if (cause == DamageCause.BLOCK_EXPLOSION && mcPermissions.getInstance().demolitionsExpertise(player)) {
                     BlastMining.demolitionsExpertise(player, event);
                 }
 
@@ -182,7 +182,10 @@ public class mcEntityListener implements Listener {
 
             if (plugin.misc.tntTracker.containsKey(id)) {
                 Player player = plugin.misc.tntTracker.get(id);
-                BlastMining.biggerBombs(player, event);
+
+                if (mcPermissions.getInstance().biggerBombs(player)) {
+                    BlastMining.biggerBombs(player, event);
+                }
             }
         }
     }

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

@@ -94,7 +94,7 @@ public class mcPlayerListener implements Listener {
                 break;
 
             case CAUGHT_ENTITY:
-                if (Users.getProfile(player).getSkillLevel(SkillType.FISHING) >= 150) {
+                if (Users.getProfile(player).getSkillLevel(SkillType.FISHING) >= 150 && mcPermissions.getInstance().shakeMob(player)) {
                     Fishing.shakeMob(event);
                 }
                 break;
@@ -223,7 +223,7 @@ public class mcPlayerListener implements Listener {
             }
 
             /* GREEN THUMB CHECK */
-            if (mcPermissions.getInstance().herbalism(player) && Herbalism.makeMossy(mat) && is.getType().equals(Material.SEEDS)) {
+            if (mcPermissions.getInstance().greenThumbBlocks(player) && Herbalism.makeMossy(mat) && is.getType().equals(Material.SEEDS)) {
                 Herbalism.greenThumbBlocks(is, player, block);
             }
 

+ 273 - 37
src/main/java/com/gmail/nossr50/mcPermissions.java

@@ -9,10 +9,34 @@ public class mcPermissions {
         return player.hasPermission(perm);
     }
 
+    public static mcPermissions getInstance() {
+        if (instance == null) {
+            instance = new mcPermissions();
+        }
+
+        return instance;
+    }
+
+    /*
+     * GENERIC PERMISSIONS
+     */
+
+    public boolean motd(Player player) {
+        return player.hasPermission("mcmmo.motd");
+    }
+
     public boolean admin(Player player) {
         return player.hasPermission("mcmmo.admin");
     }
 
+    public boolean arcaneBypass(Player player) {
+        return player.hasPermission(("mcmmo.repair.arcanebypass"));
+    }
+
+    /*
+     * MCMMO.TOOLS.*
+     */
+
     public boolean mcrefresh(Player player) {
         return player.hasPermission("mcmmo.tools.mcrefresh");
     }
@@ -25,56 +49,264 @@ public class mcPermissions {
         return player.hasPermission("mcmmo.tools.mmoedit");
     }
 
-    public boolean herbalismAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.herbalism");
+    public boolean mcgod(Player player) {
+        return player.hasPermission("mcmmo.tools.mcgod");
     }
 
-    public boolean excavationAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.excavation");
+    /*
+     * MCMMO.ABILITY.TAMING.*
+     */
+
+    public boolean fastFoodService(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.fastfoodservice");
     }
 
-    public boolean unarmedAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.unarmed");
+    public boolean sharpenedclaws(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.sharpenedclaws");
     }
 
-    public boolean chimaeraWing(Player player) {
-        return player.hasPermission("mcmmo.item.chimaerawing");
+    public boolean gore(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.gore");
     }
 
-    public boolean miningAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.mining");
+    public boolean callOfTheWild(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.callofthewild");
     }
 
-    public boolean axesAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.axes");
+    public boolean environmentallyAware(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.environmentallyaware");
     }
 
-    public boolean swordsAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.swords");
+    public boolean thickFur(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.thickfur");
     }
 
-    public boolean woodCuttingAbility(Player player) {
-        return player.hasPermission("mcmmo.ability.woodcutting");
+    public boolean shockProof(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.shockproof");
     }
 
-    public boolean mcgod(Player player) {
-        return player.hasPermission("mcmmo.tools.mcgod");
+    public boolean beastLore(Player player) {
+        return player.hasPermission("mcmmo.ability.taming.beastlore");
     }
 
-    public boolean motd(Player player) {
-        return player.hasPermission("mcmmo.motd");
+    /*
+     * MCMMO.ABILITY.FISHING.*
+     */
+
+    public boolean shakeMob(Player player) {
+        return player.hasPermission("mcmmo.ability.fishing.shakemob");
     }
 
-    public boolean mcAbility(Player player) {
-        return player.hasPermission("mcmmo.commands.ability");
+    /*
+     * MCMMO.ABILITY.MINING.*
+     */
+
+    public boolean superBreaker(Player player) {
+        return player.hasPermission("mcmmo.ability.mining.superbreaker");
     }
 
-    public boolean partyChat(Player player) {
-        return player.hasPermission("mcmmo.chat.partychat");
+    public boolean miningDoubleDrops(Player player) {
+        return player.hasPermission("mcmmo.ability.mining.doubledrops");
     }
 
-    public boolean partyLock(Player player) {
-        return player.hasPermission("mcmmo.chat.partylock");
+    /*
+     * MCMMO.ABILITY.WOODCUTTING.*
+     */
+
+    public boolean treeFeller(Player player) {
+        return player.hasPermission("mcmmo.ability.woodcutting.treefeller");
+    }
+
+    public boolean leafBlower(Player player) {
+        return player.hasPermission("mcmmo.ability.woodcutting.leafblower");
+    }
+
+    public boolean woodcuttingDoubleDrops(Player player) {
+        return player.hasPermission("mcmmo.ability.woodcutting.doubledrops");
+    }
+
+    /*
+     * MCMMO.ABILITY.REPAIR.*
+     */
+
+    public boolean repairBonus(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.repairbonus");
+    }
+
+    public boolean arcaneForging(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.arcaneforging");
+    }
+
+    public boolean stoneRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.stonerepair");
+    }
+
+    public boolean ironRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.ironrepair");
+    }
+
+    public boolean goldRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.goldrepair");
+    }
+
+    public boolean diamondRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.diamondrepair");
+    }
+
+    public boolean armorRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.armorrepair");
+    }
+
+    public boolean toolRepair(Player player) {
+        return player.hasPermission("mcmmo.ability.repair.toolrepair");
+    }
+
+    /*
+     * MCMMO.ABILITY.UNARMED.*
+     */
+
+    public boolean unarmedBonus(Player player) {
+        return player.hasPermission("mcmmo.ability.unarmed.bonusdamage");
+    }
+
+    public boolean disarm(Player player) {
+        return player.hasPermission("mcmmo.ability.unarmed.disarm");
+    }
+
+    public boolean berserk(Player player) {
+        return player.hasPermission("mcmmo.ability.unarmed.berserk");
+    }
+
+    public boolean deflect(Player player) {
+        return player.hasPermission("mcmmo.ability.unarmed.deflect");
+    }
+
+    /*
+     * MCMMO.ABILITY.ARCHERY.*
+     */
+
+    public boolean trackArrows(Player player) {
+        return player.hasPermission("mcmmo.ability.archery.trackarrows");
+    }
+
+    public boolean ignition(Player player) {
+        return player.hasPermission("mcmmo.ability.archery.ignition");
+    }
+
+    public boolean daze(Player player) {
+        return player.hasPermission("mcmmo.ability.archery.daze");
+    }
+
+    /*
+     * MCMMO.ABILITY.HERBALISM.*
+     */
+
+    public boolean herbalismDoubleDrops(Player player) {
+        return player.hasPermission("mcmmo.ability.herbalism.doubledrops");
+    }
+
+    public boolean greenTerra(Player player) {
+        return player.hasPermission("mcmmo.ability.herbalism.greenterra");
+    }
+
+    public boolean greenThumbBlocks(Player player) {
+        return player.hasPermission("mcmmo.ability.herbalism.greenthumbblocks");
+    }
+
+    public boolean greenThumbWheat(Player player) {
+        return player.hasPermission("mcmmo.ability.herbalism.greenthumbwheat");
+    }
+
+    /*
+     * MCMMO.ABILITY.EXCAVATION.*
+     */
+
+    public boolean gigaDrillBreaker(Player player) {
+        return player.hasPermission("mcmmo.ability.excavation.gigadrillbreaker");
+    }
+
+    public boolean excavationTreasures(Player player) {
+        return player.hasPermission("mcmmo.ability.excavation.treasures");
+    }
+
+    /*
+     * MCMMO.ABILITY.SWORDS.*
+     */
+
+    public boolean swordsBleed(Player player) {
+        return player.hasPermission("mcmmo.ability.swords.bleed");
+    }
+
+    public boolean serratedStrikes(Player player) {
+        return player.hasPermission("mcmmo.ability.swords.serratedstrikes");
+    }
+
+    public boolean counterAttack(Player player) {
+        return player.hasPermission("mcmmo.ability.swords.counterattack");
+    }
+
+    /*
+     * MCMMO.ABILITY.AXES.*
+     */
+
+    public boolean skullSplitter(Player player) {
+        return player.hasPermission("mcmmo.ability.axes.skullsplitter");
+    }
+
+    public boolean axeBonus(Player player) {
+        return player.hasPermission("mcmmo.ability.axes.bonusdamage");
+    }
+
+    public boolean criticalHit(Player player) {
+        return player.hasPermission("mcmmo.ability.axes.criticalhit");
+    }
+
+    public boolean impact(Player player) {
+        return player.hasPermission("mcmmo.ability.axes.impact");
+    }
+
+    /*
+     * MCMMO.ABILITY.ACROBATICS.*
+     */
+
+    public boolean roll(Player player) {
+        return player.hasPermission("mcmmo.ability.acrobatics.roll");
+    }
+
+    public boolean gracefulRoll(Player player) {
+        return player.hasPermission("mcmmo.ability.acrobatics.gracefulroll");
+    }
+
+    public boolean dodge(Player player) {
+        return player.hasPermission("mcmmo.ability.acrobatics.dodge");
+    }
+
+    /*
+     * MCMMO.ABILITY.BLASTMINING.*
+     */
+
+    public boolean biggerBombs(Player player) {
+        return player.hasPermission("mcmmo.ability.blastmining.biggerbombs");
+    }
+
+    public boolean demolitionsExpertise(Player player) {
+        return player.hasPermission("mcmmo.ability.blastmining.demolitionsexpertise");
+    }
+
+    /*
+     * MCMMO.ITEM.*
+     */
+
+    public boolean chimaeraWing(Player player) {
+        return player.hasPermission("mcmmo.item.chimaerawing");
+    }
+
+    /*
+     * MCMMO.COMMANDS.*
+     */
+
+    public boolean mcAbility(Player player) {
+        return player.hasPermission("mcmmo.commands.ability");
     }
 
     public boolean partyTeleport(Player player) {
@@ -89,18 +321,26 @@ public class mcPermissions {
         return player.hasPermission("mcmmo.commands.party");
     }
 
-    public boolean adminChat(Player player) {
-        return player.hasPermission("mcmmo.chat.adminchat");
+    /*
+     * MCMMO.CHAT.*
+     */
+
+    public boolean partyChat(Player player) {
+        return player.hasPermission("mcmmo.chat.partychat");
     }
 
-    public static mcPermissions getInstance() {
-        if (instance == null) {
-            instance = new mcPermissions();
-        }
+    public boolean partyLock(Player player) {
+        return player.hasPermission("mcmmo.chat.partylock");
+    }
 
-        return instance;
+    public boolean adminChat(Player player) {
+        return player.hasPermission("mcmmo.chat.adminchat");
     }
 
+    /*
+     * MCMMO.SKILLS.*
+     */
+
     public boolean taming(Player player) {
         return player.hasPermission("mcmmo.skills.taming");
     }
@@ -124,10 +364,6 @@ public class mcPermissions {
     public boolean repair(Player player) {
         return player.hasPermission("mcmmo.skills.repair");
     }
-    
-    public boolean repairArcaneBypass(Player player) {
-        return player.hasPermission(("mcmmo.skills.repair.arcanebypass"));
-    }
 
     public boolean unarmed(Player player) {
         return player.hasPermission("mcmmo.skills.unarmed");

+ 6 - 2
src/main/java/com/gmail/nossr50/skills/Acrobatics.java

@@ -31,11 +31,15 @@ public class Acrobatics {
         int damage = event.getDamage();
         int health = player.getHealth();
 
+        if (!mcPermissions.getInstance().gracefulRoll(player)) {
+            gracefulRoll = false;
+        }
+
         if (gracefulRoll) {
             acrovar = acrovar * 2;
         }
 
-        if (acrovar > MAX_BONUS_LEVEL || Math.random() * 1000 <= acrovar) {
+        if ((acrovar > MAX_BONUS_LEVEL || Math.random() * 1000 <= acrovar) && mcPermissions.getInstance().roll(player)) {
             int threshold = 7;
 
             if (gracefulRoll) {
@@ -99,7 +103,7 @@ public class Acrobatics {
             int skillLevel = PPd.getSkillLevel(SkillType.ACROBATICS);
             int skillCheck = m.skillCheck(skillLevel, MAX_BONUS_LEVEL);
 
-            if (Math.random() * 4000 <= skillCheck) {
+            if (Math.random() * 4000 <= skillCheck && mcPermissions.getInstance().dodge(defender)) {
                 defender.sendMessage(mcLocale.getString("Acrobatics.Dodge"));
 
                 if (System.currentTimeMillis() >= (5000 + PPd.getRespawnATS()) && defender.getHealth() >= 1) {

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

@@ -9,6 +9,7 @@ import org.bukkit.inventory.ItemStack;
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
 import com.gmail.nossr50.locale.mcLocale;
@@ -100,7 +101,7 @@ public class Archery {
             loc.setPitch(-90);
         }
 
-        if (Math.random() * 2000 <= skillCheck) {
+        if (Math.random() * 2000 <= skillCheck && mcPermissions.getInstance().daze(attacker)) {
             defender.teleport(loc);
             defender.sendMessage(mcLocale.getString("Combat.TouchedFuzzy"));
             attacker.sendMessage(mcLocale.getString("Combat.TargetDazed"));

+ 6 - 0
src/main/java/com/gmail/nossr50/skills/BlastMining.java

@@ -233,6 +233,12 @@ public class BlastMining {
         event.setDamage(damage);
     }
 
+    /**
+     * Remotely detonate TNT for Blast Mining.
+     *
+     * @param player Player detonating the TNT
+     * @param plugin mcMMO plugin instance
+     */
     public static void remoteDetonation(Player player, mcMMO plugin) {
         final byte SNOW = 78;
         final byte AIR = 0;

+ 39 - 36
src/main/java/com/gmail/nossr50/skills/Excavation.java

@@ -14,6 +14,7 @@ import org.bukkit.event.player.PlayerAnimationEvent;
 import com.gmail.nossr50.spout.SpoutStuff;
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.config.LoadProperties;
 import com.gmail.nossr50.config.LoadTreasures;
 import com.gmail.nossr50.datatypes.PlayerProfile;
@@ -61,55 +62,57 @@ public class Excavation {
         ArrayList<ItemStack> is = new ArrayList<ItemStack>();
 
         List<ExcavationTreasure> treasures = new ArrayList<ExcavationTreasure>();
-        
+
         int xp = LoadProperties.mbase;
 
-        switch (type) {
-        case DIRT:
-            treasures = LoadTreasures.excavationFromDirt;
-            break;
+        if (mcPermissions.getInstance().excavationTreasures(player)) {
+            switch (type) {
+            case DIRT:
+                treasures = LoadTreasures.excavationFromDirt;
+                break;
 
-        case GRASS:
-            treasures = LoadTreasures.excavationFromGrass;
-            break;
+            case GRASS:
+                treasures = LoadTreasures.excavationFromGrass;
+                break;
 
-        case SAND:
-            treasures = LoadTreasures.excavationFromSand;
-            break;
+            case SAND:
+                treasures = LoadTreasures.excavationFromSand;
+                break;
 
-        case GRAVEL:
-            treasures = LoadTreasures.excavationFromGravel;
-            break;
+            case GRAVEL:
+                treasures = LoadTreasures.excavationFromGravel;
+                break;
 
-        case CLAY:
-            treasures = LoadTreasures.excavationFromClay;
-            break;
+            case CLAY:
+                treasures = LoadTreasures.excavationFromClay;
+                break;
 
-        case MYCEL:
-            treasures = LoadTreasures.excavationFromMycel;
-            break;
+            case MYCEL:
+                treasures = LoadTreasures.excavationFromMycel;
+                break;
 
-        case SOUL_SAND:
-            treasures = LoadTreasures.excavationFromSoulSand;
-            break;
+            case SOUL_SAND:
+                treasures = LoadTreasures.excavationFromSoulSand;
+                break;
 
-        default:
-            break;
-        }
+            default:
+                break;
+            }
 
-        for (ExcavationTreasure treasure : treasures) {
-            if (skillLevel >= treasure.getDropLevel()) {
-                if (Math.random() * 100 <= treasure.getDropChance()) {
-                    xp += treasure.getXp();
-                    is.add(treasure.getDrop());
+            for (ExcavationTreasure treasure : treasures) {
+                if (skillLevel >= treasure.getDropLevel()) {
+                    if (Math.random() * 100 <= treasure.getDropChance()) {
+                        xp += treasure.getXp();
+                        is.add(treasure.getDrop());
+                    }
                 }
             }
-        }
 
-        //Drop items
-        for (ItemStack x : is) {
-            if (x != null) {
-                m.mcDropItem(loc, x);
+            //Drop items
+            for (ItemStack x : is) {
+                if (x != null) {
+                    m.mcDropItem(loc, x);
+                }
             }
         }
 

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

@@ -13,6 +13,7 @@ import org.bukkit.inventory.PlayerInventory;
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.config.LoadProperties;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
@@ -150,7 +151,7 @@ public class Herbalism {
                 mat = Material.WHEAT;
                 xp = LoadProperties.mwheat;
 
-                if (LoadProperties.wheatRegrowth) {
+                if (LoadProperties.wheatRegrowth && mcPermissions.getInstance().greenThumbWheat(player)) {
                     greenThumbWheat(block, player, event, plugin);
                 }
             }

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

@@ -13,6 +13,7 @@ import org.bukkit.event.player.PlayerAnimationEvent;
 
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.config.LoadProperties;
 import com.gmail.nossr50.spout.SpoutStuff;
 import com.gmail.nossr50.datatypes.PlayerProfile;
@@ -164,7 +165,7 @@ public class Mining
 
             int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.MINING);
 
-            if (MAX_BONUS_LEVEL > 1000 || (Math.random() * 1000 <= skillLevel)) {
+            if ((MAX_BONUS_LEVEL > 1000 || (Math.random() * 1000 <= skillLevel)) && mcPermissions.getInstance().miningDoubleDrops(player)) {
                 if (player.getItemInHand().containsEnchantment(Enchantment.SILK_TOUCH)) {
                     m.mcDropItem(block.getLocation(), new ItemStack(block.getType()));
                 }

+ 12 - 12
src/main/java/com/gmail/nossr50/skills/Repair.java

@@ -39,18 +39,18 @@ public class Repair {
             /*
              * REPAIR ARMOR
              */
-            if (ItemChecks.isArmor(is) && LoadProperties.repairArmor) {
-                if (ItemChecks.isDiamondArmor(is) && inventory.contains(LoadProperties.rDiamond) && skillLevel >= LoadProperties.repairdiamondlevel) {
+            if (ItemChecks.isArmor(is) && LoadProperties.repairArmor && mcPermissions.getInstance().armorRepair(player)) {
+                if (ItemChecks.isDiamondArmor(is) && inventory.contains(LoadProperties.rDiamond) && skillLevel >= LoadProperties.repairdiamondlevel && mcPermissions.getInstance().diamondRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rDiamond));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 6, true);
                 }
-                else if (ItemChecks.isIronArmor(is) && inventory.contains(LoadProperties.rIron) && skillLevel >= LoadProperties.repairIronLevel) {
+                else if (ItemChecks.isIronArmor(is) && inventory.contains(LoadProperties.rIron) && skillLevel >= LoadProperties.repairIronLevel && mcPermissions.getInstance().ironRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rIron));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 2, true);
                 }
-                else if (ItemChecks.isGoldArmor(is) && inventory.contains(LoadProperties.rGold) && skillLevel >= LoadProperties.repairGoldLevel) {
+                else if (ItemChecks.isGoldArmor(is) && inventory.contains(LoadProperties.rGold) && skillLevel >= LoadProperties.repairGoldLevel && mcPermissions.getInstance().goldRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rGold));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 4, true);
@@ -68,8 +68,8 @@ public class Repair {
             /*
              * REPAIR TOOLS
              */
-            else if (ItemChecks.isTool(is) && LoadProperties.repairTools) {
-                if (ItemChecks.isStoneTool(is) && inventory.contains(LoadProperties.rStone) && skillLevel >= LoadProperties.repairStoneLevel) {
+            else if (ItemChecks.isTool(is) && LoadProperties.repairTools && mcPermissions.getInstance().toolRepair(player)) {
+                if (ItemChecks.isStoneTool(is) && inventory.contains(LoadProperties.rStone) && skillLevel >= LoadProperties.repairStoneLevel && mcPermissions.getInstance().stoneRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rStone));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 2, false);
@@ -79,17 +79,17 @@ public class Repair {
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 2, false);
                 }
-                else if (ItemChecks.isIronTool(is) && inventory.contains(LoadProperties.rIron) && skillLevel >= LoadProperties.repairIronLevel) {
+                else if (ItemChecks.isIronTool(is) && inventory.contains(LoadProperties.rIron) && skillLevel >= LoadProperties.repairIronLevel && mcPermissions.getInstance().ironRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rIron));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 1, true);
                 }
-                else if (ItemChecks.isDiamondTool(is) && inventory.contains(LoadProperties.rDiamond) && skillLevel >= LoadProperties.repairdiamondlevel) {
+                else if (ItemChecks.isDiamondTool(is) && inventory.contains(LoadProperties.rDiamond) && skillLevel >= LoadProperties.repairdiamondlevel && mcPermissions.getInstance().diamondRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rDiamond));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 1, true);
                 }
-                else if (ItemChecks.isGoldTool(is) && inventory.contains(LoadProperties.rGold) && skillLevel >= LoadProperties.repairGoldLevel) {
+                else if (ItemChecks.isGoldTool(is) && inventory.contains(LoadProperties.rGold) && skillLevel >= LoadProperties.repairGoldLevel && mcPermissions.getInstance().goldRepair(player)) {
                     inventory.removeItem(new ItemStack(LoadProperties.rGold));
                     repairItem(player, is);
                     xpHandler(player, PP, is, durabilityBefore, 8, true);
@@ -188,7 +188,7 @@ public class Repair {
 
         int rank = getArcaneForgingRank(Users.getProfile(player).getSkillLevel(SkillType.REPAIR));
 
-        if (rank == 0) {
+        if (rank == 0 || !mcPermissions.getInstance().arcaneForging(player)) {
             for (Enchantment x : enchants.keySet()) {
                 is.removeEnchantment(x);
             }
@@ -410,7 +410,7 @@ public class Repair {
 
         int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.REPAIR);
 
-        if(skillLevel > MAX_BONUS_LEVEL || (Math.random() * 1000 <= skillLevel)) {
+        if ((skillLevel > MAX_BONUS_LEVEL || (Math.random() * 1000 <= skillLevel)) && mcPermissions.getInstance().repairBonus(player)) {
             player.sendMessage(mcLocale.getString("Skills.FeltEasy"));
             return true;
         }
@@ -428,7 +428,7 @@ public class Repair {
     public static void repairItem(Player player, ItemStack is) {
 
         /* Handle the enchants */
-        if (LoadProperties.mayLoseEnchants && !mcPermissions.getInstance().repairArcaneBypass(player)) {
+        if (LoadProperties.mayLoseEnchants && !mcPermissions.getInstance().arcaneBypass(player)) {
             addEnchants(player, is);
         }
 

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

@@ -91,7 +91,7 @@ public class Swords {
             Player defender = (Player) target;
             PlayerProfile PPd = Users.getProfile(defender);
 
-            if (ItemChecks.isSword(defender.getItemInHand()) && mcPermissions.getInstance().swords(defender)) {
+            if (ItemChecks.isSword(defender.getItemInHand()) && mcPermissions.getInstance().counterAttack(defender)) {
                 final int MAX_BONUS_LEVEL = 600;
                 final int COUNTER_ATTACK_MODIFIER = 2;
 

+ 54 - 15
src/main/java/com/gmail/nossr50/skills/Taming.java

@@ -9,6 +9,7 @@ import org.bukkit.entity.LivingEntity;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Tameable;
 import org.bukkit.entity.Wolf;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
 import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
 import org.bukkit.inventory.ItemStack;
@@ -17,6 +18,7 @@ import org.bukkit.metadata.FixedMetadataValue;
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.config.LoadProperties;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
@@ -104,7 +106,7 @@ public class Taming {
      * @param theWolf The wolf whose owner's name to get
      * @return the name of the wolf's owner, or "Offline Master" if the owner is offline
      */
-    public static String getOwnerName(Wolf theWolf) {
+    private static String getOwnerName(Wolf theWolf) {
         AnimalTamer tamer = theWolf.getOwner();
 
         if (tamer instanceof Player) {
@@ -140,41 +142,51 @@ public class Taming {
         case CONTACT:
         case LAVA:
         case FIRE:
-            if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) {
-                if (event.getDamage() >= wolf.getHealth()) {
-                    return;
-                }
+            if (mcPermissions.getInstance().environmentallyAware(master)) {
+                if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) {
+                    if (event.getDamage() >= wolf.getHealth()) {
+                        return;
+                    }
 
-                wolf.teleport(master.getLocation());
-                master.sendMessage(mcLocale.getString("mcEntityListener.WolfComesBack"));
+                    wolf.teleport(master.getLocation());
+                    master.sendMessage(mcLocale.getString("mcEntityListener.WolfComesBack"));
+                }
             }
             break;
 
         case FALL:
-            if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) {
-                event.setCancelled(true);
+            if (mcPermissions.getInstance().environmentallyAware(master)) {
+                if (skillLevel >= ENVIRONMENTALLY_AWARE_LEVEL) {
+                    event.setCancelled(true);
+                }
             }
             break;
 
         /* Thick Fur */
         case FIRE_TICK:
-            if(skillLevel >= THICK_FUR_LEVEL) {
-                wolf.setFireTicks(0);
+            if (mcPermissions.getInstance().thickFur(master)) {
+                if(skillLevel >= THICK_FUR_LEVEL) {
+                    wolf.setFireTicks(0);
+                }
             }
             break;
 
         case ENTITY_ATTACK:
         case PROJECTILE:
-            if (skillLevel >= THICK_FUR_LEVEL) {
-                event.setDamage(event.getDamage() / THICK_FUR_MODIFIER);
+            if (mcPermissions.getInstance().thickFur(master)) {
+                if (skillLevel >= THICK_FUR_LEVEL) {
+                    event.setDamage(event.getDamage() / THICK_FUR_MODIFIER);
+                }
             }
             break;
 
         /* Shock Proof */
         case ENTITY_EXPLOSION:
         case BLOCK_EXPLOSION:
-            if (skillLevel >= SHOCK_PROOF_LEVEL) {
-                event.setDamage(event.getDamage() / SHOCK_PROOF_MODIFIER);
+            if (mcPermissions.getInstance().shockProof(master)) {
+                if (skillLevel >= SHOCK_PROOF_LEVEL) {
+                    event.setDamage(event.getDamage() / SHOCK_PROOF_MODIFIER);
+                }
             }
             break;
 
@@ -229,4 +241,31 @@ public class Taming {
             }
         }
     }
+
+    /**
+     * Inspect a tamed animal for details.
+     *
+     * @param event
+     * @param target
+     */
+    public static void beastLore(EntityDamageByEntityEvent event, LivingEntity target, Player attacker) {
+
+        //TODO: Make this work for Ocelots
+        if (target.getType().equals(EntityType.WOLF)) {
+            Wolf wolf = (Wolf) target;
+            String message = mcLocale.getString("Combat.BeastLore") + " ";
+            int health = wolf.getHealth();
+            event.setCancelled(true);
+
+            if (wolf.isTamed()) {
+                message = message.concat(mcLocale.getString("Combat.BeastLoreOwner", new Object[] {getOwnerName(wolf)}) + " ");
+                message = message.concat(mcLocale.getString("Combat.BeastLoreHealthWolfTamed", new Object[] {health}));
+            }
+            else {
+                message = message.concat(mcLocale.getString("Combat.BeastLoreHealthWolf", new Object[] {health}));
+            }
+
+            attacker.sendMessage(message);
+        }
+    }
 }

+ 20 - 0
src/main/java/com/gmail/nossr50/skills/Unarmed.java

@@ -5,7 +5,9 @@ import org.bukkit.entity.Player;
 import org.bukkit.event.entity.EntityDamageByEntityEvent;
 import org.bukkit.inventory.ItemStack;
 
+import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
 import com.gmail.nossr50.locale.mcLocale;
@@ -54,4 +56,22 @@ public class Unarmed {
             }
         }
     }
+
+    /**
+     * Check for arrow deflection.
+     *
+     * @param defender The defending player
+     * @param event The event to modify
+     */
+    public static void deflectCheck(Player defender, EntityDamageByEntityEvent event) {
+        final int MAX_BONUS_LEVEL = 1000;
+
+        int skillLevel = Users.getProfile(defender).getSkillLevel(SkillType.UNARMED);
+        int skillCheck = m.skillCheck(skillLevel, MAX_BONUS_LEVEL);
+
+        if (Math.random() * 2000 <= skillCheck && mcPermissions.getInstance().deflect(defender)) {
+            event.setCancelled(true);
+            defender.sendMessage(mcLocale.getString("Combat.ArrowDeflect"));
+        }
+    }
 }

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

@@ -15,6 +15,7 @@ import org.bukkit.Bukkit;
 import com.gmail.nossr50.Combat;
 import com.gmail.nossr50.Users;
 import com.gmail.nossr50.m;
+import com.gmail.nossr50.mcPermissions;
 import com.gmail.nossr50.config.LoadProperties;
 import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
@@ -248,7 +249,7 @@ public class WoodCutting {
         byte type = block.getData();
         Material mat = Material.getMaterial(block.getTypeId());
 
-        if (skillLevel > MAX_SKILL_LEVEL || Math.random() * 1000 <= skillLevel) {
+        if ((skillLevel > MAX_SKILL_LEVEL || Math.random() * 1000 <= skillLevel) && mcPermissions.getInstance().woodcuttingDoubleDrops(player)) {
             ItemStack item = new ItemStack(mat, 1, (short) 0, type);
             m.mcDropItem(block.getLocation(), item);
         }

+ 207 - 27
src/main/resources/plugin.yml

@@ -40,6 +40,7 @@ commands:
         description: Shows your mcMMO stats and xp
     mcremove:
         description: Remove a user from the database
+        permission: mcmmo.tools.mcremove
     mmoedit:
         description: Edit the skill values for a user
         permission: mcmmo.tools.mmoedit
@@ -98,7 +99,8 @@ permissions:
             #Instead of containing mcmmo.defaultsop on its own, it should specify each of mcmmo.defaultsop
             mcmmo.admin: true
             mcmmo.tools.*: true
-            mcmmo.chat.adminchat: true 
+            mcmmo.chat.adminchat: true
+            mcmmo.repair.arcanebypass: true
     mcmmo.defaults:
         default: true
         description: mcmmo permisions that default to true
@@ -116,50 +118,228 @@ permissions:
             mcmmo.chat.adminchat: true
             mcmmo.admin: true
             mcmmo.tools.*: true
+            mcmmo.repair.arcanebypass: true
     mcmmo.admin:
         description: Allows access to mmoupdate and other sensitive commands        
+    mcmmo.repair.arcanebypass:
+        description: Allows user to bypass Arcane Repair so he will never lose enchantments
     mcmmo.tools.*:
         description: Implies all mcmmo.tools permissions.
         children:
             mcmmo.tools.mcrefresh: true 
             mcmmo.tools.mmoedit: true 
-            mcmmo.tools.mcgod: true 
+            mcmmo.tools.mcgod: true
+            mcmmo.tools.mcremove: true
     mcmmo.tools.mcrefresh:
         description: Allows access to mcrefresh command
     mcmmo.tools.mmoedit:
         description: Allows access to mmoedit command
     mcmmo.tools.mcgod:
-        description: Allows access to mcgod command        
+        description: Allows access to mcgod command
+    mcmmo.tools.mcremove:
+        decription: Allows access to mcremove command
     mcmmo.ability.*:
         description: Implies all mcmmo.ability permissions.
         children:
-            mcmmo.ability.herbalism: true 
-            mcmmo.ability.excavation: true 
-            mcmmo.ability.unarmed: true 
-            mcmmo.ability.mining: true 
-            mcmmo.ability.axes: true 
-            mcmmo.ability.swords: true 
-            mcmmo.ability.woodcutting: true 
-    mcmmo.ability.herbalism:
-        description: Allows access to Green Terra ability
-    mcmmo.ability.excavation:
-        description: Allows access to Giga Drill Breaker ability
-    mcmmo.ability.unarmed:
-        description: Allows access to Berserker ability
-    mcmmo.ability.mining:
-        description: Allows access to Super Breaker ability
-    mcmmo.ability.axes:
-        description: Allows access to Skull Splitter ability
-    mcmmo.ability.swords:
-        description: Allows access to Serrated Strikes ability
-    mcmmo.ability.woodcutting:
-        description: Allows access to Tree Feller ability        
+            mcmmo.ability.taming.*: true
+            mcmmo.ability.fishing.*: true
+            mcmmo.ability.mining.*: true
+            mcmmo.ability.woodcutting.*: true
+            mcmmo.ability.repair.*: true
+            mcmmo.ability.unarmed.*: true
+            mcmmo.ability.archery.*: true
+            mcmmo.ability.herbalism.*: true
+            mcmmo.ability.excavation.*: true
+            mcmmo.ability.swords.*: true
+            mcmmo.ability.axes.*: true
+            mcmmo.ability.acrobatics.*: true
+            mcmmo.ability.blastmining.*: true
+    mcmmo.ability.taming.*:
+        description: Allows access to all Taming abilities
+        children:
+            mcmmo.ability.taming.fastfoodservice: true
+            mcmmo.ability.taming.sharpenedclaws: true
+            mcmmo.ability.taming.gore: true
+            mcmmo.ability.taming.callofthewild: true
+            mcmmo.ability.taming.environmentallyaware: true
+            mcmmo.ability.taming.thickfur: true
+            mcmmo.ability.taming.shockproof: true
+            mcmmo.ability.taming.beastlore: true
+    mcmmo.ability.taming.fastfoodservice:
+        description: Allows access to the Fast Food Service ability
+    mcmmo.ability.taming.sharpenedclaws:
+        description: Allows access to the Sharpened Claws ability
+    mcmmo.ability.taming.gore:
+        description: Allows access to the Gore ability
+    mcmmo.ability.taming.callofthewild:
+        description: Allows access to the Call of the Wild ability
+    mcmmo.ability.taming.environmentallyaware:
+        description: Allows access to the Environmentally Aware ability
+    mcmmo.ability.taming.thickfur:
+        description: Allows access to the Thick Fur ability
+    mcmmo.ability.taming.shockproof:
+        description: Allows access to the Shock Proof ability
+    mcmmo.ability.taming.beastlore:
+        description: Allows access to the Beast Lore ability
+    mcmmo.ability.fishing.*:
+        description: Allows access to all Fishing abilities
+        children:
+            mcmmo.ability.fishing.shakemob: true
+    mcmmo.ability.fishing.shakemob:
+        description: Allows access to the Shake Mob ability
+    mcmmo.ability.mining.*:
+        description: Allows access to all Mining abilities
+        children:
+            mcmmo.ability.mining.superbreaker: true
+            mcmmo.ability.mining.doubledrops: true
+    mcmmo.ability.mining.superbreaker:
+        description: Allows access to the Super Breaker ability
+    mcmmo.ability.mining.doubledrops:
+        description: Allows double drop chance when mining
+    mcmmo.ability.woodcutting.*:
+        description: Allows access to all Woodcutting abilities
+        children:
+            mcmmo.ability.woodcutting.treefeller: true
+            mcmmo.ability.woodcutting.leafblower: true
+            mcmmo.ability.woodcutting.doubledrops: true
+    mcmmo.ability.woodcutting.treefeller:
+        description: Allows access to Tree Feller ability
+    mcmmo.ability.woodcutting.leafblower:
+        description: Allows access to Leaf Blower ability
+    mcmmo.ability.woodcutting.doubledrops:
+        description: Allows double drop chance when woodcutting
+    mcmmo.ability.repair.*:
+        description: Allows access to all Repair abilities
+        children:
+            mcmmo.ability.repair.repairbonus: true
+            mcmmo.ability.repair.arcaneforging: true
+            mcmmo.ability.repair.stonerepair: true
+            mcmmo.ability.repair.ironrepair: true
+            mcmmo.ability.repair.goldrepair: true
+            mcmmo.ability.repair.diamondrepair: true
+            mcmmo.ability.repair.armorrepair: true
+            mcmmo.ability.repair.toolrepair: true
+    mcmmo.ability.repair.repairbonus:
+        description: Allows access to Super Repair bonus
+    mcmmo.ability.repair.arcaneforging:
+        description: Allows access to the Arcane Forging ability
+    mcmmo.ability.repair.stonerepair:
+        description: Allows ability to repair Stone tools
+    mcmmo.ability.repair.ironrepair:
+        description: Allows ability to repair Iron tools & armor
+    mcmmo.ability.repair.goldrepair:
+        description: Allows ability to repair Gold tools & armor
+    mcmmo.ability.repair.diamondrepair:
+        description: Allows ability to repair Diamond tools & armor
+    mcmmo.ability.repair.armorrepair:
+        description: Allows ability to repair armor
+    mcmmo.ability.repair.toolrepair:
+        description: Allows ability to repair tools
+    mcmmo.ability.unarmed.*:
+        description: Allows access to all Unarmed abilities
+        children:
+            mcmmo.ability.unarmed.bonusdamage: true
+            mcmmo.ability.unarmed.disarm: true
+            mcmmo.ability.unarmed.berserk: true
+            mcmmo.ability.unarmed.deflect: true
+    mcmmo.ability.unarmed.bonusdamage:
+        description: Allows bonus damage from Unarmed
+    mcmmo.ability.unarmed.disarm:
+        description: Allows access to the Disarm ability
+    mcmmo.ability.unarmed.berserk:
+        description: Allows access to the Berserker ability
+    mcmmo.ability.unarmed.deflect:
+        description: Allows access to the Deflect ability
+    mcmmo.ability.archery.*:
+        description: Allows access to all Archery abilities
+        children:
+            mcmmo.ability.archery.trackarrows: true
+            mcmmo.ability.archery.ignition: true
+            mcmmo.ability.archery.daze: true
+    mcmmo.ability.archery.trackarrows:
+        description: Allows tracking & retrieval of arrows
+    mcmmo.ability.archery.ignition:
+        description: Allows access to the Ignition ability
+    mcmmo.ability.archery.daze:
+        description: Allows access to the Daze ability
+    mcmmo.ability.herbalism.*:
+        description: Allows access to all Herbalism abilities
+        children:
+            mcmmo.ability.herbalism.doubledrops: true
+            mcmmo.ability.herbalism.greenterra: true
+            mcmmo.ability.herbalism.greenthumbblocks: true
+            mcmmo.ability.herbalism.greenthumbwheat: true
+    mcmmo.ability.herbalism.doubledrops:
+        description: Allows double drop chance from Herbalism
+    mcmmo.ability.herbalism.greenterra:
+        description: Allows access to the Green Terra ability
+    mcmmo.ability.herbalism.greenthumbblocks:
+        description: Allows access to the Green Thumb ability for blocks
+    mcmmo.ability.herbalism.greenthumbwheat:
+        description: Allows access to the Green Thumb ability for wheat
+    mcmmo.ability.excavation.*:
+        description: Allows access to all Excavation abilities
+        children:
+            mcmmo.ability.excavation.gigadrillbreaker: true
+            mcmmo.ability.excavation.treasures: true
+    mcmmo.ability.excavation.gigadrillbreaker:
+        description: Allows access to the Giga Drill Breaker ability
+    mcmmo.ability.excavation.treasures:
+        description: Allows treasure drops from Excavation
+    mcmmo.ability.swords.*:
+        description: Allows access to all Swords abilities
+        children:
+            mcmmo.ability.swords.bleed: true
+            mcmmo.ability.swords.serratedstrikes: true
+            mcmmo.ability.swords.counterattack: true
+    mcmmo.ability.swords.bleed:
+        description: Allows access to the Bleed ability
+    mcmmo.ability.swords.serratedstrikes:
+        description: Allows access to the Serrated Strikes ability
+    mcmmo.ability.swords.counterattack:
+        description: Allows access to the Counter Attack ability
+    mcmmo.ability.axes.*:
+        description: Allows access to all Axes abilities
+        children:
+            mcmmo.ability.axes.skullsplitter: true
+            mcmmo.ability.axes.bonusdamage: true
+            mcmmo.ability.axes.critalhit: true
+            mcmmo.ability.axes.impact: true
+    mcmmo.ability.axes.skullsplitter:
+        description: Allows access to the Skull Splitter ability
+    mcmmo.ability.axes.bonusdamage:
+        description: Allows bonus damage from Axes
+    mcmmo.ability.axes.criticalhit:
+        description: Allows access to the Critical Hit ability
+    mcmmo.ability.axes.skullsplitter:
+        description: Allows access to the Impact ability
+    mcmmo.ability.acrobatics.*:
+        description: Allows access to all Acrobatics abilities
+        children:
+            mcmmo.ability.acrobatics.roll: true
+            mcmmo.ability.acrobatics.gracefulroll: true
+            mcmmo.ability.acrobatics.dodge: true
+    mcmmo.ability.acrobatics.roll:
+        description: Allows access to the Roll ability
+    mcmmo.ability.acrobatics.gracefulroll:
+        description: Allows access to the Graceful Roll ability
+    mcmmo.ability.acrobatics.dodge:
+        description: Allows access to the Dodge ability
+    mcmmo.ability.blastmining.*:
+        description: Allows access to all Blast Mining abilities
+        children:
+            mcmmo.ability.blastmining.biggerbombs: true
+            mcmmo.ability.blastmining.demolitionsexpertise: true
+    mcmmo.ability.blastmining.biggerbombs:
+        description: Allows access to the Bigger Bombs ability
+    mcmmo.ability.blastmining.demolitionsexpertise:
+        description: Allows access to the Demolitions Expertise ability
     mcmmo.item.*:
         description: Implies all mcmmo.item permissions.
         children:
             mcmmo.item.chimaerawing: true 
     mcmmo.item.chimaerawing:
-        description: Allows use of Chimaera Wing item            
+        description: Allows use of Chimaera Wing item
     mcmmo.motd:
         description: Allows access to the motd        
     mcmmo.commands.*:
@@ -202,6 +382,8 @@ permissions:
             mcmmo.skills.axes: true 
             mcmmo.skills.acrobatics: true
             mcmmo.skills.blastmining: true
+    mcmmo.skills.fishing:
+        description: Allows access to the Fishing skill
     mcmmo.skills.taming:
         description: Allows access to the Taming skill
     mcmmo.skills.mining:
@@ -210,8 +392,6 @@ permissions:
         description: Allows access to the Woodcutting skill
     mcmmo.skills.repair:
         description: Allows access to the Repair skill
-    mcmmo.skills.repair.arcanebypass:
-        description: Allows user to bypass Arcane Repair so he will never lose enchantments
     mcmmo.skills.unarmed:
         description: Allows access to the Unarmed skill
     mcmmo.skills.archery: