Browse Source

Add Mother Lode mastery subskill to Mining

nossr50 4 years ago
parent
commit
1ff2c0dcfc
22 changed files with 147 additions and 68 deletions
  1. 17 1
      Changelog.txt
  2. 3 2
      src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java
  3. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java
  4. 5 4
      src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java
  5. 5 5
      src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java
  6. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java
  7. 7 6
      src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java
  8. 4 4
      src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java
  9. 16 1
      src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java
  10. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
  11. 3 2
      src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java
  12. 0 11
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  13. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java
  14. 4 4
      src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java
  15. 8 8
      src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java
  16. 5 5
      src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java
  17. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java
  18. 29 0
      src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
  19. 3 2
      src/main/java/com/gmail/nossr50/util/BlockUtils.java
  20. 14 0
      src/main/java/com/gmail/nossr50/util/Permissions.java
  21. 5 0
      src/main/resources/advanced.yml
  22. 7 1
      src/main/resources/locale/locale_en_US.properties

+ 17 - 1
Changelog.txt

@@ -1,5 +1,7 @@
 Version 2.1.175
-    Added a new mastery sub-skill to each skill (see notes)
+    Added a set of "mastery" subskills meant for end game progression
+    Added the mastery subskill 'Mother Lode' to Mining
+    Added the mastery subskill 'Clean Cuts' to Woodcutting
     Added /mmopower command (aliases /mmopowerlevel /powerlevel)
     Added 'mcmmo.commands.mmopower' permission node
     Added 'mcmmo.ability.acrobatics.mastery' permission node
@@ -18,15 +20,29 @@ Version 2.1.175
     Added 'mcmmo.ability.taming.mastery' permission node
     Added 'mcmmo.ability.unarmed.mastery' permission node
     Added 'mcmmo.ability.woodcutting.mastery' permission node
+    Added 'Mining.SubSkill.Mastery.Name' to locale
+    Added 'Mining.SubSkill.Mastery.Stat' to locale
+    Added 'Mining.SubSkill.Mastery.Description' to locale
+    Added 'Woodcutting.SubSkill.Mastery.Name' to locale
+    Added 'Woodcutting.SubSkill.Mastery.Stat' to locale
+    Added 'Woodcutting.SubSkill.Mastery.Description' to locale
 
     Added 'General.PowerLevel.Skill_Mastery.Enabled' to config.yml which is used to enable or disable the mastery skills (will also disable the new power level command)
 
     NOTES:
+    The goal of this update is to provide a small benefit to each skill and a reason to grind past the "maximum", ideally for a long while.
     Most skills have a mastery sub-skill, this mastery subskill provides a small benefit that scales to level 10,000 (or 1,000 for standard) and does not have ranks (other than the initial rank to unlock it)
     Mastery skills unlock at level 1000 for RetroMode (the default setting), and 100 for Standard, you can edit this via skillranks.yml
     Mastery skills are meant to provide an "end-game" to skills, a reason to continue leveling a skill past its "max".
     This system is brand new, it is entirely possible I will completely change, remove, or add more mastery skills in the future.
 
+    The section below assumes RetroMode, if you are using Standard mode (1-100) just divide level examples by 10.
+
+    Mastery Skills
+    Mining (Mastery Triple Drops): With default settings, when players hit level 1,000 they will unlock this sub-skill, it will add a 1% chance to get triple drops while mining (this can be edited in advanced.yml), this skill maxes out at 10.0% chance at level 10,000.
+    This skill respects double drop settings from the config files.
+    Double Drops only occur if the Triple Drops fail, these two skills do not stack.
+
     New Power Level Command
     This power level command gives you a view of all your current masteries, it also provides a summary of your power level.
 

+ 3 - 2
src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java

@@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
 import com.gmail.nossr50.listeners.InteractionManager;
 import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.random.RandomChanceSkill;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.skills.SkillActivationType;
@@ -38,8 +39,8 @@ public class AcrobaticsCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canDodge = canUseSubskill(player, SubSkillType.ACROBATICS_DODGE);
-        canRoll = canUseSubskill(player, SubSkillType.ACROBATICS_ROLL);
+        canDodge = Permissions.canUseSubSkill(player, SubSkillType.ACROBATICS_DODGE);
+        canRoll = Permissions.canUseSubSkill(player, SubSkillType.ACROBATICS_ROLL);
     }
 
     @Override

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java

@@ -68,8 +68,8 @@ public class AlchemyCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canCatalysis = canUseSubskill(player, SubSkillType.ALCHEMY_CATALYSIS);
-        canConcoctions = canUseSubskill(player, SubSkillType.ALCHEMY_CONCOCTIONS);
+        canCatalysis = Permissions.canUseSubSkill(player, SubSkillType.ALCHEMY_CATALYSIS);
+        canConcoctions = Permissions.canUseSubSkill(player, SubSkillType.ALCHEMY_CONCOCTIONS);
     }
 
     @Override

+ 5 - 4
src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java

@@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.archery.Archery;
+import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.text.TextComponentFactory;
@@ -52,9 +53,9 @@ public class ArcheryCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canSkillShot = canUseSubskill(player, SubSkillType.ARCHERY_SKILL_SHOT);
-        canDaze = canUseSubskill(player, SubSkillType.ARCHERY_DAZE);
-        canRetrieve = canUseSubskill(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL);
+        canSkillShot = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_SKILL_SHOT);
+        canDaze = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_DAZE);
+        canRetrieve = Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_ARROW_RETRIEVAL);
     }
 
     @Override
@@ -75,7 +76,7 @@ public class ArcheryCommand extends SkillCommand {
             messages.add(getStatMessage(SubSkillType.ARCHERY_SKILL_SHOT, skillShotBonus));
         }
 
-        if(canUseSubskill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) {
+        if(Permissions.canUseSubSkill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) {
             messages.add(getStatMessage(SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK,
                 String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, 1000))));
         }

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

@@ -64,10 +64,10 @@ public class AxesCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(Player player) {
         canSkullSplitter = Permissions.skullSplitter(player) && RankUtils.hasUnlockedSubskill(player, SubSkillType.AXES_SKULL_SPLITTER);
-        canCritical = canUseSubskill(player, SubSkillType.AXES_CRITICAL_STRIKES);
-        canAxeMastery = canUseSubskill(player, SubSkillType.AXES_AXE_MASTERY);
-        canImpact = canUseSubskill(player, SubSkillType.AXES_ARMOR_IMPACT);
-        canGreaterImpact = canUseSubskill(player, SubSkillType.AXES_GREATER_IMPACT);
+        canCritical = Permissions.canUseSubSkill(player, SubSkillType.AXES_CRITICAL_STRIKES);
+        canAxeMastery = Permissions.canUseSubSkill(player, SubSkillType.AXES_AXE_MASTERY);
+        canImpact = Permissions.canUseSubSkill(player, SubSkillType.AXES_ARMOR_IMPACT);
+        canGreaterImpact = Permissions.canUseSubSkill(player, SubSkillType.AXES_GREATER_IMPACT);
     }
 
     @Override
@@ -96,7 +96,7 @@ public class AxesCommand extends SkillCommand {
                     + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : ""));
         }
 
-        if(canUseSubskill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) {
+        if(Permissions.canUseSubSkill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) {
             messages.add(getStatMessage(SubSkillType.AXES_AXES_LIMIT_BREAK,
                     String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.AXES_AXES_LIMIT_BREAK, 1000))));
         }

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

@@ -38,7 +38,7 @@ public class ExcavationCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(Player player) {
         canGigaDrill = Permissions.gigaDrillBreaker(player) && RankUtils.hasUnlockedSubskill(player, SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER);
-        canTreasureHunt = canUseSubskill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY);
+        canTreasureHunt = Permissions.canUseSubSkill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY);
     }
 
     @Override
@@ -54,7 +54,7 @@ public class ExcavationCommand extends SkillCommand {
             //messages.add(LocaleLoader.getString("Excavation.Effect.Length", gigaDrillBreakerLength) + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", gigaDrillBreakerLengthEndurance) : ""));
         }
 
-        if(canUseSubskill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY)) {
+        if(Permissions.canUseSubSkill(player, SubSkillType.EXCAVATION_ARCHAEOLOGY)) {
             messages.add(getStatMessage(false, false, SubSkillType.EXCAVATION_ARCHAEOLOGY,
                     percent.format(excavationManager.getArchaelogyExperienceOrbChance() / 100.0D)));
             messages.add(getStatMessage(true, false, SubSkillType.EXCAVATION_ARCHAEOLOGY,

+ 7 - 6
src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java

@@ -7,6 +7,7 @@ import com.gmail.nossr50.datatypes.treasure.Rarity;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.fishing.FishingManager;
+import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.skills.RankUtils;
@@ -98,12 +99,12 @@ public class FishingCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canTreasureHunt = canUseSubskill(player, SubSkillType.FISHING_TREASURE_HUNTER);
-        canMagicHunt = canUseSubskill(player, SubSkillType.FISHING_MAGIC_HUNTER) && canUseSubskill(player, SubSkillType.FISHING_TREASURE_HUNTER);
-        canShake = canUseSubskill(player, SubSkillType.FISHING_SHAKE);
-        canFishermansDiet = canUseSubskill(player, SubSkillType.FISHING_FISHERMANS_DIET);
-        canMasterAngler = mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && canUseSubskill(player, SubSkillType.FISHING_MASTER_ANGLER);
-        canIceFish = canUseSubskill(player, SubSkillType.FISHING_ICE_FISHING);
+        canTreasureHunt = Permissions.canUseSubSkill(player, SubSkillType.FISHING_TREASURE_HUNTER);
+        canMagicHunt = Permissions.canUseSubSkill(player, SubSkillType.FISHING_MAGIC_HUNTER) && Permissions.canUseSubSkill(player, SubSkillType.FISHING_TREASURE_HUNTER);
+        canShake = Permissions.canUseSubSkill(player, SubSkillType.FISHING_SHAKE);
+        canFishermansDiet = Permissions.canUseSubSkill(player, SubSkillType.FISHING_FISHERMANS_DIET);
+        canMasterAngler = mcMMO.getCompatibilityManager().getMasterAnglerCompatibilityLayer() != null && Permissions.canUseSubSkill(player, SubSkillType.FISHING_MASTER_ANGLER);
+        canIceFish = Permissions.canUseSubSkill(player, SubSkillType.FISHING_ICE_FISHING);
     }
 
     @Override

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

@@ -88,13 +88,13 @@ public class HerbalismCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        hasHylianLuck = canUseSubskill(player, SubSkillType.HERBALISM_HYLIAN_LUCK);
+        hasHylianLuck = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_HYLIAN_LUCK);
         canGreenTerra = Permissions.greenTerra(player);
         canGreenThumbPlants = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbPlant(player, Material.WHEAT) || Permissions.greenThumbPlant(player, Material.CARROT) || Permissions.greenThumbPlant(player, Material.POTATO) || Permissions.greenThumbPlant(player, Material.BEETROOT) || Permissions.greenThumbPlant(player, Material.NETHER_WART) || Permissions.greenThumbPlant(player, Material.COCOA));
         canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbBlock(player, Material.DIRT) || Permissions.greenThumbBlock(player, Material.COBBLESTONE) || Permissions.greenThumbBlock(player, Material.COBBLESTONE_WALL) || Permissions.greenThumbBlock(player, Material.STONE_BRICKS));
-        canFarmersDiet = canUseSubskill(player, SubSkillType.HERBALISM_FARMERS_DIET);
-        canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled();
-        canShroomThumb = canUseSubskill(player, SubSkillType.HERBALISM_SHROOM_THUMB);
+        canFarmersDiet = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_FARMERS_DIET);
+        canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled();
+        canShroomThumb = Permissions.canUseSubSkill(player, SubSkillType.HERBALISM_SHROOM_THUMB);
     }
 
     @Override

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

@@ -18,6 +18,8 @@ import java.util.List;
 public class MiningCommand extends SkillCommand {
     private String doubleDropChance;
     private String doubleDropChanceLucky;
+    private String masteryTripleDropChance;
+    private String masteryTripleDropChanceLucky;
     private String superBreakerLength;
     private String superBreakerLengthEndurance;
 
@@ -51,6 +53,14 @@ public class MiningCommand extends SkillCommand {
             blastDamageDecrease = percent.format(miningManager.getBlastDamageModifier() / 100.0D);
             blastRadiusIncrease = miningManager.getBlastRadiusModifier();
         }
+
+        // Mastery TRIPLE DROPS
+        if (Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) {
+            String[] masteryTripleDropStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.MINING_MASTERY);
+            masteryTripleDropChance = masteryTripleDropStrings[0];
+            masteryTripleDropChanceLucky = masteryTripleDropStrings[1];
+        }
+
         
         // DOUBLE DROPS
         if (canDoubleDrop) {
@@ -72,7 +82,7 @@ public class MiningCommand extends SkillCommand {
         canBiggerBombs = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BIGGER_BOMBS) && Permissions.biggerBombs(player);
         canBlast = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_BLAST_MINING) && Permissions.remoteDetonation(player);
         canDemoExpert = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_DEMOLITIONS_EXPERTISE) && Permissions.demolitionsExpertise(player);
-        canDoubleDrop = canUseSubskill(player, SubSkillType.MINING_DOUBLE_DROPS);
+        canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.MINING_DOUBLE_DROPS);
         canSuperBreaker = RankUtils.hasUnlockedSubskill(player, SubSkillType.MINING_SUPER_BREAKER) && Permissions.superBreaker(player);
     }
 
@@ -94,6 +104,11 @@ public class MiningCommand extends SkillCommand {
             messages.add(getStatMessage(SubSkillType.MINING_DEMOLITIONS_EXPERTISE, blastDamageDecrease));
             //messages.add(LocaleLoader.getString("Mining.Effect.Decrease", blastDamageDecrease));
         }
+
+        if(Permissions.canUseSubSkill(player, SubSkillType.MINING_MASTERY)) {
+            messages.add(getStatMessage(SubSkillType.MINING_MASTERY, masteryTripleDropChance)
+                    + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", masteryTripleDropChanceLucky) : ""));
+        }
         
         if (canDoubleDrop) {
             messages.add(getStatMessage(SubSkillType.MINING_DOUBLE_DROPS, doubleDropChance)

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

@@ -76,9 +76,9 @@ public class RepairCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canSuperRepair = canUseSubskill(player, SubSkillType.REPAIR_SUPER_REPAIR);
-        canMasterRepair = canUseSubskill(player, SubSkillType.REPAIR_REPAIR_MASTERY);
-        canArcaneForge = canUseSubskill(player, SubSkillType.REPAIR_ARCANE_FORGING);
+        canSuperRepair = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_SUPER_REPAIR);
+        canMasterRepair = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_REPAIR_MASTERY);
+        canArcaneForge = Permissions.canUseSubSkill(player, SubSkillType.REPAIR_ARCANE_FORGING);
         canRepairDiamond = Permissions.repairMaterialType(player, MaterialType.DIAMOND);
         canRepairGold = Permissions.repairMaterialType(player, MaterialType.GOLD);
         canRepairIron = Permissions.repairMaterialType(player, MaterialType.IRON);

+ 3 - 2
src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java

@@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.salvage.Salvage;
 import com.gmail.nossr50.skills.salvage.SalvageManager;
+import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
@@ -30,8 +31,8 @@ public class SalvageCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canScrapCollector = canUseSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR);
-        canArcaneSalvage = canUseSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE);
+        canScrapCollector = Permissions.canUseSubSkill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR);
+        canArcaneSalvage = Permissions.canUseSubSkill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE);
     }
 
     @Override

+ 0 - 11
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -14,7 +14,6 @@ import com.gmail.nossr50.util.player.UserManager;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.gmail.nossr50.util.skills.PerksUtils;
-import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
@@ -285,14 +284,4 @@ public abstract class SkillCommand implements TabExecutor {
 
     protected abstract List<Component> getTextComponents(Player player);
 
-    /**
-     * Checks if a player can use a skill
-     * @param player target player
-     * @param subSkillType target subskill
-     * @return true if the player has permission and has the skill unlocked
-     */
-    protected boolean canUseSubskill(Player player, SubSkillType subSkillType)
-    {
-        return Permissions.isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType);
-    }
 }

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

@@ -54,8 +54,8 @@ public class SmeltingCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canFuelEfficiency = canUseSubskill(player, SubSkillType.SMELTING_FUEL_EFFICIENCY);
-        canSecondSmelt = canUseSubskill(player, SubSkillType.SMELTING_SECOND_SMELT);
+        canFuelEfficiency = Permissions.canUseSubSkill(player, SubSkillType.SMELTING_FUEL_EFFICIENCY);
+        canSecondSmelt = Permissions.canUseSubSkill(player, SubSkillType.SMELTING_SECOND_SMELT);
         //canFluxMine = canUseSubskill(player, SubSkillType.SMELTING_FLUX_MINING);
         canUnderstandTheArt = Permissions.vanillaXpBoost(player, skill) && RankUtils.hasUnlockedSubskill(player, SubSkillType.SMELTING_UNDERSTANDING_THE_ART);
     }

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

@@ -61,8 +61,8 @@ public class SwordsCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canBleed = canUseSubskill(player, SubSkillType.SWORDS_RUPTURE);
-        canCounter = canUseSubskill(player, SubSkillType.SWORDS_COUNTER_ATTACK);
+        canBleed = Permissions.canUseSubSkill(player, SubSkillType.SWORDS_RUPTURE);
+        canCounter = Permissions.canUseSubSkill(player, SubSkillType.SWORDS_COUNTER_ATTACK);
         canSerratedStrike = RankUtils.hasUnlockedSubskill(player, SubSkillType.SWORDS_SERRATED_STRIKES) && Permissions.serratedStrikes(player);
     }
 
@@ -95,13 +95,13 @@ public class SwordsCommand extends SkillCommand {
                     + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", serratedStrikesLengthEndurance) : ""));
         }
 
-        if(canUseSubskill(player, SubSkillType.SWORDS_STAB))
+        if(Permissions.canUseSubSkill(player, SubSkillType.SWORDS_STAB))
         {
             messages.add(getStatMessage(SubSkillType.SWORDS_STAB,
                     String.valueOf(UserManager.getPlayer(player).getSwordsManager().getStabDamage())));
         }
 
-        if(canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) {
+        if(Permissions.canUseSubSkill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) {
             messages.add(getStatMessage(SubSkillType.SWORDS_SWORDS_LIMIT_BREAK,
                     String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, 1000))));
         }

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

@@ -43,15 +43,15 @@ public class TamingCommand extends SkillCommand {
 
     @Override
     protected void permissionsCheck(Player player) {
-        canBeastLore = canUseSubskill(player, SubSkillType.TAMING_BEAST_LORE);
+        canBeastLore = Permissions.canUseSubSkill(player, SubSkillType.TAMING_BEAST_LORE);
         canCallWild = Permissions.callOfTheWild(player, EntityType.HORSE) || Permissions.callOfTheWild(player, EntityType.WOLF) || Permissions.callOfTheWild(player, EntityType.OCELOT);
-        canEnvironmentallyAware = canUseSubskill(player, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE);
-        canFastFood = canUseSubskill(player, SubSkillType.TAMING_FAST_FOOD_SERVICE);
-        canGore = canUseSubskill(player, SubSkillType.TAMING_GORE);
-        canSharpenedClaws = canUseSubskill(player, SubSkillType.TAMING_SHARPENED_CLAWS);
-        canShockProof = canUseSubskill(player, SubSkillType.TAMING_SHOCK_PROOF);
-        canThickFur = canUseSubskill(player, SubSkillType.TAMING_THICK_FUR);
-        canHolyHound = canUseSubskill(player, SubSkillType.TAMING_HOLY_HOUND);
+        canEnvironmentallyAware = Permissions.canUseSubSkill(player, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE);
+        canFastFood = Permissions.canUseSubSkill(player, SubSkillType.TAMING_FAST_FOOD_SERVICE);
+        canGore = Permissions.canUseSubSkill(player, SubSkillType.TAMING_GORE);
+        canSharpenedClaws = Permissions.canUseSubSkill(player, SubSkillType.TAMING_SHARPENED_CLAWS);
+        canShockProof = Permissions.canUseSubSkill(player, SubSkillType.TAMING_SHOCK_PROOF);
+        canThickFur = Permissions.canUseSubSkill(player, SubSkillType.TAMING_THICK_FUR);
+        canHolyHound = Permissions.canUseSubSkill(player, SubSkillType.TAMING_HOLY_HOUND);
     }
 
     @Override

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

@@ -75,10 +75,10 @@ public class UnarmedCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(Player player) {
         canBerserk = RankUtils.hasUnlockedSubskill(player, SubSkillType.UNARMED_BERSERK) && Permissions.berserk(player);
-        canIronArm = canUseSubskill(player, SubSkillType.UNARMED_STEEL_ARM_STYLE);
-        canDeflect = canUseSubskill(player, SubSkillType.UNARMED_ARROW_DEFLECT);
-        canDisarm = canUseSubskill(player, SubSkillType.UNARMED_DISARM);
-        canIronGrip = canUseSubskill(player, SubSkillType.UNARMED_IRON_GRIP);
+        canIronArm = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_STEEL_ARM_STYLE);
+        canDeflect = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_ARROW_DEFLECT);
+        canDisarm = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_DISARM);
+        canIronGrip = Permissions.canUseSubSkill(player, SubSkillType.UNARMED_IRON_GRIP);
         // TODO: Apparently we forgot about block cracker?
     }
 
@@ -114,7 +114,7 @@ public class UnarmedCommand extends SkillCommand {
             //messages.add(LocaleLoader.getString("Unarmed.Ability.Chance.IronGrip", ironGripChance) + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", ironGripChanceLucky) : ""));
         }
 
-        if(canUseSubskill(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) {
+        if(Permissions.canUseSubSkill(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) {
             messages.add(getStatMessage(SubSkillType.UNARMED_UNARMED_LIMIT_BREAK,
                     String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, 1000))));
         }

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

@@ -55,9 +55,9 @@ public class WoodcuttingCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(Player player) {
         canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player);
-        canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1;
-        canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER);
-        canKnockOnWood = canTreeFell && canUseSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD);
+        canDoubleDrop = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1;
+        canLeafBlow = Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER);
+        canKnockOnWood = canTreeFell && Permissions.canUseSubSkill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD);
         /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER);
         canBarkSurgeon = canUseSubskill(player, SubSkillType.WOODCUTTING_BARK_SURGEON);
         canNaturesBounty = canUseSubskill(player, SubSkillType.WOODCUTTING_NATURES_BOUNTY);*/

+ 29 - 0
src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java

@@ -28,6 +28,7 @@ import org.bukkit.entity.Player;
 import org.bukkit.entity.TNTPrimed;
 import org.bukkit.event.entity.EntityExplodeEvent;
 import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -68,6 +69,11 @@ public class MiningManager extends SkillManager {
         return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS) && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS);
     }
 
+    public boolean canMiningMastery() {
+        return Permissions.canUseSubSkill(getPlayer(), SubSkillType.MINING_MASTERY);
+    }
+
+
     /**
      * Process double drops & XP gain for Mining.
      *
@@ -94,6 +100,29 @@ public class MiningManager extends SkillManager {
         if(silkTouch && !AdvancedConfig.getInstance().getDoubleDropSilkTouchEnabled())
             return;
 
+        //Mining mastery allows for a chance of triple drops
+        if(canMiningMastery()) {
+            //Triple Drops failed so do a normal double drops check
+            if(!processTripleDrops(blockState)) {
+                processDoubleDrops(blockState);
+            }
+        } else {
+            //If the user has no mastery, proceed with normal double drop routine
+            processDoubleDrops(blockState);
+        }
+    }
+
+    private boolean processTripleDrops(@NotNull BlockState blockState) {
+        //TODO: Make this readable
+        if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_MASTERY, true)) {
+            BlockUtils.markDropsAsBonus(blockState, 2);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private void processDoubleDrops(@NotNull BlockState blockState) {
         //TODO: Make this readable
         if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) {
             boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops();

+ 3 - 2
src/main/java/com/gmail/nossr50/util/BlockUtils.java

@@ -16,6 +16,7 @@ import org.bukkit.block.BlockState;
 import org.bukkit.block.data.Ageable;
 import org.bukkit.block.data.BlockData;
 import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.HashSet;
 
@@ -30,7 +31,7 @@ public final class BlockUtils {
      * @param blockState target blockstate
      * @param triple     marks the block to give triple drops
      */
-    public static void markDropsAsBonus(BlockState blockState, boolean triple) {
+    public static void markDropsAsBonus(@NotNull BlockState blockState, boolean triple) {
         if (triple)
             blockState.setMetadata(mcMMO.BONUS_DROPS_METAKEY, new BonusDropMeta(2, mcMMO.p));
         else
@@ -42,7 +43,7 @@ public final class BlockUtils {
      * @param blockState target blockstate
      * @param amount amount of extra items to drop
      */
-    public static void markDropsAsBonus(BlockState blockState, int amount) {
+    public static void markDropsAsBonus(@NotNull BlockState blockState, int amount) {
             blockState.setMetadata(mcMMO.BONUS_DROPS_METAKEY, new BonusDropMeta(amount, mcMMO.p));
     }
 

+ 14 - 0
src/main/java/com/gmail/nossr50/util/Permissions.java

@@ -7,14 +7,17 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
 import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.util.skills.RankUtils;
 import org.bukkit.Material;
 import org.bukkit.Server;
 import org.bukkit.World;
 import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
 import org.bukkit.permissions.Permissible;
 import org.bukkit.permissions.Permission;
 import org.bukkit.permissions.PermissionDefault;
 import org.bukkit.plugin.PluginManager;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.Locale;
 
@@ -234,4 +237,15 @@ public final class Permissions {
         permission.setDefault(permissionDefault);
         pluginManager.addPermission(permission);
     }
+
+    /**
+     * Checks if a player can use a skill
+     *
+     * @param player target player
+     * @param subSkillType target subskill
+     * @return true if the player has permission and has the skill unlocked
+     */
+    public static boolean canUseSubSkill(@NotNull Player player, @NotNull SubSkillType subSkillType) {
+        return isSubSkillEnabled(player, subSkillType) && RankUtils.hasUnlockedSubskill(player, subSkillType);
+    }
 }

+ 5 - 0
src/main/resources/advanced.yml

@@ -281,6 +281,11 @@ Skills:
     #  Settings for Mining
     ###
     Mining:
+        Mastery:
+            MaxBonusLevel:
+                Standard: 1000
+                RetroMode: 10000
+            ChanceMax: 10.0
         SuperBreaker:
             AllowTripleDrops: true
         DoubleDrops:

+ 7 - 1
src/main/resources/locale/locale_en_US.properties

@@ -312,6 +312,9 @@ Mining.SubSkill.SuperBreaker.Stat=Super Breaker Length
 Mining.SubSkill.DoubleDrops.Name=Double Drops
 Mining.SubSkill.DoubleDrops.Description=Double the normal loot
 Mining.SubSkill.DoubleDrops.Stat=Double Drop Chance
+Mining.SubSkill.Mastery.Name=Mother Lode
+Mining.SubSkill.Mastery.Description=Triple the normal loot
+Mining.SubSkill.Mastery.Stat=Mother Lode Chance
 Mining.SubSkill.BlastMining.Name=Blast Mining
 Mining.SubSkill.BlastMining.Description=Bonuses to mining with TNT
 Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2})
@@ -539,8 +542,11 @@ Woodcutting.SubSkill.KnockOnWood.Stat=Knock on Wood
 Woodcutting.SubSkill.KnockOnWood.Loot.Normal=Standard loot from trees
 Woodcutting.SubSkill.KnockOnWood.Loot.Rank2=Standard loot from trees and experience orbs
 Woodcutting.SubSkill.HarvestLumber.Name=Harvest Lumber
-Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract more Lumber
+Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract up to double the Lumber
 Woodcutting.SubSkill.HarvestLumber.Stat=Double Drop Chance
+Woodcutting.SubSkill.Mastery.Name=Clean Cuts
+Woodcutting.SubSkill.Mastery.Description=Masterfully extract up to triple the Lumber
+Woodcutting.SubSkill.Mastery.Stat=Triple Drop Chance
 Woodcutting.SubSkill.Splinter.Name=Splinter
 Woodcutting.SubSkill.Splinter.Description=Cut down trees more efficiently.
 Woodcutting.SubSkill.BarkSurgeon.Name=Bark Surgeon