Browse Source

Added Limit Break to Archery, Axes, Swords, Unarmed

nossr50 6 years ago
parent
commit
658382dba2

+ 14 - 1
Changelog.txt

@@ -8,12 +8,25 @@ Key:
   - Removal
 
 Version 2.1.26
+    Added new scaling damage buffs to all existing Combat Skills
+    Fixed a bug where Berserk was not adding 50% damage to attacks
+
     Changed how Iron Arm damage is calculated (Rank 1 now effectively gives twice the damage bonus it used to, with a net result of 3 extra RAW damage before reductions)
+    XP is not granted for attacks while attacking with vanilla attack speed cooldown
     Added a new subskill named Stab to Swords to help with lategame PVP combat
-    New permission node 'mcmmo.ability.swords.stab'
+    New permission node ''
     NOTE: Combat skills will be completely configurable in the upcoming 2.2 update, be patient <3
 
+    New Permissions
+            - mcmmo.ability.unarmed.unarmedlimitbreak
+            - mcmmo.ability.axes.axeslimitbreak
+            - mcmmo.ability.archery.archerylimitbreak
+            - mcmmo.ability.swords.swordslimitbreak
+            - mcmmo.ability.swords.stab
+
     Notes:
+    The new Limit Break subskills are intended to make Prot IV players less tanky and for you to feel more powerful for having high skill level.
+
     I collected several sets of data before making these changes, including damage to player with and without prot 4 diamond armor, damage to those players with and without enchanted weapons, damage with and without leveling your skills, and combinations of the previously mentioned things.
     These changes are meant to be minor tweaks for endgame PVP, a dedicated PVP update where I do a lot more research and testing will happen after 2.3
 

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

@@ -5,6 +5,7 @@ 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.TextComponentFactory;
+import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import net.md_5.bungee.api.chat.TextComponent;
 import org.bukkit.entity.Player;
@@ -74,6 +75,11 @@ public class ArcheryCommand extends SkillCommand {
             messages.add(getStatMessage(SubSkillType.ARCHERY_SKILL_SHOT, skillShotBonus));
         }
 
+        if(canUseSubskill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) {
+            messages.add(getStatMessage(SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK,
+                    String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK))));
+        }
+
         return messages;
     }
 

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

@@ -7,6 +7,7 @@ import com.gmail.nossr50.skills.axes.Axes;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.TextComponentFactory;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import net.md_5.bungee.api.chat.TextComponent;
@@ -95,6 +96,11 @@ public class AxesCommand extends SkillCommand {
                     + (hasEndurance ? LocaleLoader.getString("Perks.ActivationTime.Bonus", skullSplitterLengthEndurance) : ""));
         }
 
+        if(canUseSubskill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) {
+            messages.add(getStatMessage(SubSkillType.AXES_AXES_LIMIT_BREAK,
+                    String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.AXES_AXES_LIMIT_BREAK))));
+        }
+
         return messages;
     }
 

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

@@ -7,6 +7,7 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.TextComponentFactory;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import net.md_5.bungee.api.chat.TextComponent;
@@ -100,6 +101,11 @@ public class SwordsCommand extends SkillCommand {
                     String.valueOf(UserManager.getPlayer(player).getSwordsManager().getStabDamage())));
         }
 
+        if(canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) {
+            messages.add(getStatMessage(SubSkillType.SWORDS_SWORDS_LIMIT_BREAK,
+                    String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK))));
+        }
+
         return messages;
     }
 

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

@@ -6,6 +6,7 @@ import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.TextComponentFactory;
 import com.gmail.nossr50.util.player.UserManager;
+import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
 import net.md_5.bungee.api.chat.TextComponent;
@@ -113,6 +114,11 @@ 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)) {
+            messages.add(getStatMessage(SubSkillType.UNARMED_UNARMED_LIMIT_BREAK,
+                    String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK))));
+        }
+
         return messages;
     }
 

+ 4 - 4
src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java

@@ -40,9 +40,9 @@ public enum PrimarySkillType {
     ALCHEMY(AlchemyManager.class, Color.FUCHSIA,
             ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)),
     ARCHERY(ArcheryManager.class, Color.MAROON,
-            ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)),
+            ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)),
     AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE,
-            ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)),
+            ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)),
     EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL,
             ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)),
     FISHING(FishingManager.class, Color.NAVY,
@@ -58,11 +58,11 @@ public enum PrimarySkillType {
     SMELTING(SmeltingManager.class, Color.YELLOW,
             ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)),
     SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, ToolType.SWORD,
-            ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)),
+            ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)),
     TAMING(TamingManager.class, Color.PURPLE,
             ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)),
     UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS,
-            ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_IRON_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)),
+            ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_IRON_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)),
     WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE,
             ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER));
 

+ 4 - 0
src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java

@@ -18,10 +18,12 @@ public enum SubSkillType {
     ARCHERY_ARROW_RETRIEVAL(1),
     ARCHERY_DAZE,
     ARCHERY_SKILL_SHOT(20),
+    ARCHERY_ARCHERY_LIMIT_BREAK(10),
 
     /* Axes */
     AXES_ARMOR_IMPACT(20),
     AXES_AXE_MASTERY(4),
+    AXES_AXES_LIMIT_BREAK(10),
     AXES_CRITICAL_STRIKES(1),
     AXES_GREATER_IMPACT(1),
     AXES_SKULL_SPLITTER(1),
@@ -72,6 +74,7 @@ public enum SubSkillType {
     SWORDS_RUPTURE(4),
     SWORDS_SERRATED_STRIKES(1),
     SWORDS_STAB(2),
+    SWORDS_SWORDS_LIMIT_BREAK(10),
 
     /* Taming */
     TAMING_BEAST_LORE(1),
@@ -92,6 +95,7 @@ public enum SubSkillType {
     UNARMED_DISARM(1),
     UNARMED_IRON_ARM_STYLE(5),
     UNARMED_IRON_GRIP(1),
+    UNARMED_UNARMED_LIMIT_BREAK(10),
 
     /* Woodcutting */
 /*    WOODCUTTING_BARK_SURGEON(3),*/

+ 27 - 3
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -187,7 +187,7 @@ public class EntityListener implements Listener {
         }
     }
 
-/*    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
+    /*@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
     public void onEntityDamageDebugLowest(EntityDamageEvent event)
     {
         if(event instanceof FakeEntityDamageByEntityEvent)
@@ -196,7 +196,8 @@ public class EntityListener implements Listener {
         if(event instanceof FakeEntityDamageEvent)
             return;
 
-        Bukkit.broadcastMessage(ChatColor.GOLD+"DMG Before Events: "+ChatColor.RESET+event.getDamage());
+        Bukkit.broadcastMessage(ChatColor.DARK_AQUA+"DMG Before Events: "
+                +ChatColor.RESET+event.getDamage());
     }
 
     @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -208,9 +209,30 @@ public class EntityListener implements Listener {
         if(event instanceof FakeEntityDamageEvent)
             return;
 
+        if(!(event.getEntity() instanceof LivingEntity))
+            return;
+
+        LivingEntity entity = (LivingEntity) event.getEntity();
+
         double rawDamage = event.getDamage();
         double dmgAfterReduction = event.getFinalDamage();
-        Bukkit.broadcastMessage(ChatColor.GOLD+"DEBUG: " + event.getEntity().getName()+ChatColor.RESET+"RawDMG["+rawDamage+"], "+"FinalDMG=["+dmgAfterReduction+"]");
+
+        Bukkit.broadcastMessage(ChatColor.GOLD+"DMG After Events: "
+                + event.getEntity().getName()+ChatColor.RESET
+                +"RawDMG["+rawDamage+"], "
+                +"FinalDMG=["+dmgAfterReduction+"]");
+
+        Bukkit.broadcastMessage(
+                event.getEntity().getName()
+                +ChatColor.GREEN
+                +" HP "
+                +ChatColor.RESET
+                +entity.getHealth()
+                +ChatColor.YELLOW
+                +" -> "
+                +ChatColor.RESET
+                +(entity.getHealth()-event.getFinalDamage()));
+
         Bukkit.broadcastMessage("");
     }*/
 
@@ -381,6 +403,8 @@ public class EntityListener implements Listener {
                 }
             }
         }
+
+
     }
 
     /**

+ 59 - 23
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent;
 import com.gmail.nossr50.events.fake.FakeEntityDamageEvent;
 import com.gmail.nossr50.mcMMO;
@@ -46,6 +47,7 @@ public final class CombatUtils {
         McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         SwordsManager swordsManager = mcMMOPlayer.getSwordsManager();
         double initialDamage = event.getDamage();
+        double finalDamage = initialDamage;
 
         Map<DamageModifier, Double> modifiers = getModifiers(event);
 
@@ -63,13 +65,19 @@ public final class CombatUtils {
         //Add Stab Damage
         if(swordsManager.canUseStab())
         {
-            event.setDamage(swordsManager.getStabDamage() + initialDamage);
+            finalDamage+=swordsManager.getStabDamage();
         }
 
         if (swordsManager.canUseSerratedStrike()) {
             swordsManager.serratedStrikes(target, initialDamage, modifiers);
         }
 
+        if(canUseLimitBreak(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK))
+        {
+            finalDamage+=getLimitBreakDamage(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK);
+        }
+
+        applyScaledModifiers(initialDamage, finalDamage, event);
         startGainXp(mcMMOPlayer, target, PrimarySkillType.SWORDS);
     }
 
@@ -90,24 +98,29 @@ public final class CombatUtils {
         }
 
         if (axesManager.canUseAxeMastery()) {
-            finalDamage += axesManager.axeMastery();
-        }
-
-        if (axesManager.canCriticalHit(target)) {
-            finalDamage += axesManager.criticalHit(target, initialDamage);
+            finalDamage+=axesManager.axeMastery();
         }
 
         if (axesManager.canImpact(target)) {
             axesManager.impactCheck(target);
         }
         else if (axesManager.canGreaterImpact(target)) {
-            finalDamage += axesManager.greaterImpact(target);
+            finalDamage+=axesManager.greaterImpact(target);
         }
 
         if (axesManager.canUseSkullSplitter(target)) {
             axesManager.skullSplitterCheck(target, initialDamage, modifiers);
         }
 
+        if (axesManager.canCriticalHit(target)) {
+            finalDamage+=axesManager.criticalHit(target, finalDamage);
+        }
+
+        if(canUseLimitBreak(player, SubSkillType.AXES_AXES_LIMIT_BREAK))
+        {
+            finalDamage+=getLimitBreakDamage(player, SubSkillType.AXES_AXES_LIMIT_BREAK);
+        }
+
         applyScaledModifiers(initialDamage, finalDamage, event);
         startGainXp(mcMMOPlayer, target, PrimarySkillType.AXES);
     }
@@ -116,7 +129,7 @@ public final class CombatUtils {
         if (event.getCause() == DamageCause.THORNS) {
             return;
         }
-        
+
         double initialDamage = event.getDamage();
         double finalDamage = initialDamage;
 
@@ -127,25 +140,29 @@ public final class CombatUtils {
             mcMMOPlayer.checkAbilityActivation(PrimarySkillType.UNARMED);
         }
 
-        //Only execute bonuses if the player is not spamming
         if(unarmedManager.isPunchingCooldownOver())
         {
+            //Only execute bonuses if the player is not spamming
             if (unarmedManager.canUseIronArm()) {
-                finalDamage += unarmedManager.ironArm();
+                finalDamage+=unarmedManager.ironArm();
             }
 
             if (unarmedManager.canUseBerserk()) {
-                finalDamage += unarmedManager.berserkDamage(initialDamage);
+                finalDamage+=unarmedManager.berserkDamage(finalDamage);
             }
 
             if (unarmedManager.canDisarm(target)) {
                 unarmedManager.disarmCheck((Player) target);
             }
+
+            if(canUseLimitBreak(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK))
+            {
+                finalDamage+=getLimitBreakDamage(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK);
+            }
         }
 
         applyScaledModifiers(initialDamage, finalDamage, event);
         startGainXp(mcMMOPlayer, target, PrimarySkillType.UNARMED);
-
         Unarmed.lastAttacked = System.currentTimeMillis(); //Track how often the player is punching
     }
 
@@ -163,11 +180,11 @@ public final class CombatUtils {
         tamingManager.pummel(target, wolf);
 
         if (tamingManager.canUseSharpenedClaws()) {
-            finalDamage += tamingManager.sharpenedClaws();
+            finalDamage+=tamingManager.sharpenedClaws();
         }
 
         if (tamingManager.canUseGore()) {
-            finalDamage += tamingManager.gore(target, initialDamage);
+            finalDamage+=tamingManager.gore(target, initialDamage);
         }
 
         applyScaledModifiers(initialDamage, finalDamage, event);
@@ -176,10 +193,11 @@ public final class CombatUtils {
 
     private static void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Arrow arrow) {
         double initialDamage = event.getDamage();
-        double finalDamage = initialDamage;
 
         McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         ArcheryManager archeryManager = mcMMOPlayer.getArcheryManager();
+        
+        double finalDamage = event.getDamage();
 
         if (target instanceof Player && PrimarySkillType.UNARMED.getPVPEnabled()) {
             UnarmedManager unarmedManager = UserManager.getPlayer((Player) target).getUnarmedManager();
@@ -194,17 +212,22 @@ public final class CombatUtils {
         }
 
         if (archeryManager.canSkillShot()) {
-            finalDamage += archeryManager.skillShot(initialDamage);
+            finalDamage+=archeryManager.skillShot(initialDamage);
         }
 
         if (archeryManager.canDaze(target)) {
-            finalDamage += archeryManager.daze((Player) target);
+            finalDamage+=archeryManager.daze((Player) target);
         }
 
         if (!arrow.hasMetadata(mcMMO.infiniteArrowKey) && archeryManager.canRetrieveArrows()) {
             archeryManager.retrieveArrows(target);
         }
 
+        if(canUseLimitBreak(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK))
+        {
+            finalDamage+=getLimitBreakDamage(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK);
+        }
+
         double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow);
 
         applyScaledModifiers(initialDamage, finalDamage, event);
@@ -217,8 +240,7 @@ public final class CombatUtils {
      * @param event The event to run the combat checks on.
      */
     public static void processCombatAttack(EntityDamageByEntityEvent event, Entity attacker, LivingEntity target) {
-        Entity damager = event.getDamager();
-        EntityType entityType = damager.getType();
+        EntityType entityType = attacker.getType();
 
         if (attacker instanceof Player && entityType == EntityType.PLAYER) {
             Player player = (Player) attacker;
@@ -275,7 +297,7 @@ public final class CombatUtils {
         }
 
         else if (entityType == EntityType.WOLF) {
-            Wolf wolf = (Wolf) damager;
+            Wolf wolf = (Wolf) attacker;
             AnimalTamer tamer = wolf.getOwner();
 
             if (tamer != null && tamer instanceof Player && PrimarySkillType.TAMING.shouldProcess(target)) {
@@ -287,7 +309,7 @@ public final class CombatUtils {
             }
         }
         else if (entityType == EntityType.ARROW) {
-            Arrow arrow = (Arrow) damager;
+            Arrow arrow = (Arrow) attacker;
             ProjectileSource projectileSource = arrow.getShooter();
 
             if (projectileSource != null && projectileSource instanceof Player && PrimarySkillType.ARCHERY.shouldProcess(target)) {
@@ -328,13 +350,27 @@ public final class CombatUtils {
 
                 SwordsManager swordsManager = mcMMOPlayer.getSwordsManager();
 
-                if (swordsManager.canUseCounterAttack(damager)) {
-                    swordsManager.counterAttackChecks((LivingEntity) damager, event.getDamage());
+                if (swordsManager.canUseCounterAttack(attacker)) {
+                    swordsManager.counterAttackChecks((LivingEntity) attacker, event.getDamage());
                 }
             }
         }
     }
 
+    public static int getLimitBreakDamage(Player player, SubSkillType subSkillType) {
+        return RankUtils.getRank(player, subSkillType);
+    }
+
+    /**
+     * Checks if player has access to their weapons limit break
+     * @param player target player
+     * @return true if the player has access to the limit break
+     */
+    public static boolean canUseLimitBreak(Player player, SubSkillType subSkillType) {
+        return RankUtils.hasUnlockedSubskill(player, subSkillType)
+                && Permissions.isSubSkillEnabled(player, subSkillType);
+    }
+
     /**
      * Attempt to damage target for value dmg with reason CUSTOM
      *

+ 12 - 0
src/main/resources/locale/locale_en_US.properties

@@ -166,6 +166,9 @@ Archery.SubSkill.Daze.Stat=Daze Chance
 Archery.SubSkill.ArrowRetrieval.Name=Arrow Retrieval
 Archery.SubSkill.ArrowRetrieval.Description=Chance to retrieve arrows from corpses
 Archery.SubSkill.ArrowRetrieval.Stat=Arrow Recovery Chance
+Archery.SubSkill.ArcheryLimitBreak.Name=Archery Limit Break
+Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits.
+Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Bonus DMG
 Archery.Listener=Archery:
 Archery.SkillName=ARCHERY
 #AXES
@@ -190,6 +193,9 @@ Axes.SubSkill.CriticalStrikes.Description=Double Damage
 Axes.SubSkill.CriticalStrikes.Stat=Critical Strike Chance
 Axes.SubSkill.AxeMastery.Name=Axe Mastery
 Axes.SubSkill.AxeMastery.Description=Adds bonus DMG
+Axes.SubSkill.AxesLimitBreak.Name=Axes Limit Break
+Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits.
+Axes.SubSkill.AxesLimitBreak.Stat=Limit Break Bonus DMG
 Axes.SubSkill.ArmorImpact.Name=Armor Impact
 Axes.SubSkill.ArmorImpact.Description=Strike with enough force to shatter armor
 Axes.SubSkill.GreaterImpact.Name=Greater Impact
@@ -407,6 +413,9 @@ Swords.SubSkill.Rupture.Description=Apply a powerful bleed DoT
 Swords.SubSkill.Stab.Name=Stab
 Swords.SubSkill.Stab.Description=Adds bonus damage to your attacks.
 Swords.SubSkill.Stab.Stat=Stab Damage
+Swords.SubSkill.SwordsLimitBreak.Name=Swords Limit Break
+Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits.
+Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break Bonus DMG
 Swords.SubSkill.Rupture.Stat=Rupture Chance
 Swords.SubSkill.Rupture.Stat.Extra=Rupture: [[GREEN]]{0} ticks [{1} DMG vs Player] [{2} DMG vs Mobs]
 Swords.Effect.4=Serrated Strikes Rupture+
@@ -483,6 +492,9 @@ Unarmed.SubSkill.Berserk.Stat=Berserk Length
 Unarmed.SubSkill.Disarm.Name=Disarm
 Unarmed.SubSkill.Disarm.Description=Drops the foes item held in hand
 Unarmed.SubSkill.Disarm.Stat=Disarm Chance
+Unarmed.SubSkill.UnarmedLimitBreak.Name=Unarmed Limit Break
+Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits.
+Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break Bonus DMG
 Unarmed.SubSkill.IronArmStyle.Name=Iron Arm Style
 Unarmed.SubSkill.IronArmStyle.Description=Hardens your arm over time
 Unarmed.SubSkill.ArrowDeflect.Name=Arrow Deflect

+ 14 - 0
src/main/resources/plugin.yml

@@ -248,6 +248,9 @@ permissions:
             mcmmo.ability.archery.skillshot: true
             mcmmo.ability.archery.daze: true
             mcmmo.ability.archery.arrowretrieval: true
+            mcmmo.ability.archery.archerylimitbreak: true
+    mcmmo.ability.archery.archerylimitbreak:
+        description: Adds damage to bows and crossbows
     mcmmo.ability.archery.skillshot:
         description: Allows bonus damage from the Archery SkillShot ability
     mcmmo.ability.archery.daze:
@@ -267,6 +270,9 @@ permissions:
             mcmmo.ability.axes.greaterimpact: true
             mcmmo.ability.axes.armorimpact: true
             mcmmo.ability.axes.skullsplitter: true
+            mcmmo.ability.axes.axeslimitbreak: true
+    mcmmo.ability.axes.axeslimitbreak:
+        description: Adds damage to axes
     mcmmo.ability.axes.axemastery:
         description: Allows bonus damage from Axes
     mcmmo.ability.axes.criticalhit:
@@ -564,6 +570,11 @@ permissions:
             mcmmo.ability.swords.stab: true
             mcmmo.ability.swords.counterattack: true
             mcmmo.ability.swords.serratedstrikes: true
+            mcmmo.ability.swords.swordslimitbreak: true
+    mcmmo.ability.swords.stab:
+        description: Adds damage to swords
+    mcmmo.ability.swords.swordslimitbreak:
+        description: Adds damagee to swords
     mcmmo.ability.swords.rupture:
         description: Allows access to the Bleed ability
     mcmmo.ability.swords.counterattack:
@@ -640,6 +651,9 @@ permissions:
             mcmmo.ability.unarmed.arrowdeflect: true
             mcmmo.ability.unarmed.disarm: true
             mcmmo.ability.unarmed.irongrip: true
+            mcmmo.ability.unarmed.unarmedlimitbreak: true
+    mcmmo.ability.unarmed.unarmedlimitbreak:
+        description: Adds damage to unarmed attacks
     mcmmo.ability.unarmed.berserk:
         description: Allows access to the Berserker ability
     mcmmo.ability.unarmed.blockcracker:

+ 92 - 0
src/main/resources/skillranks.yml

@@ -31,6 +31,29 @@ Alchemy:
             Rank_7: 850
             Rank_8: 1000
 Archery:
+    ArcheryLimitBreak:
+        Standard:
+            Rank_1: 10
+            Rank_2: 20
+            Rank_3: 30
+            Rank_4: 40
+            Rank_5: 50
+            Rank_6: 60
+            Rank_7: 70
+            Rank_8: 80
+            Rank_9: 90
+            Rank_10: 100
+        RetroMode:
+            Rank_1: 100
+            Rank_2: 200
+            Rank_3: 300
+            Rank_4: 400
+            Rank_5: 500
+            Rank_6: 600
+            Rank_7: 700
+            Rank_8: 800
+            Rank_9: 900
+            Rank_10: 1000
     ArrowRetrieval:
         Standard:
             Rank_1: 2
@@ -86,6 +109,29 @@ Acrobatics:
         RetroMode:
             Rank_1: 20
 Axes:
+    AxesLimitBreak:
+        Standard:
+            Rank_1: 10
+            Rank_2: 20
+            Rank_3: 30
+            Rank_4: 40
+            Rank_5: 50
+            Rank_6: 60
+            Rank_7: 70
+            Rank_8: 80
+            Rank_9: 90
+            Rank_10: 100
+        RetroMode:
+            Rank_1: 100
+            Rank_2: 200
+            Rank_3: 300
+            Rank_4: 400
+            Rank_5: 500
+            Rank_6: 600
+            Rank_7: 700
+            Rank_8: 800
+            Rank_9: 900
+            Rank_10: 1000
     SkullSplitter:
         Standard:
             Rank_1: 5
@@ -381,6 +427,29 @@ Fishing:
             Rank_7: 850
             Rank_8: 1000
 Swords:
+    SwordsLimitBreak:
+        Standard:
+            Rank_1: 10
+            Rank_2: 20
+            Rank_3: 30
+            Rank_4: 40
+            Rank_5: 50
+            Rank_6: 60
+            Rank_7: 70
+            Rank_8: 80
+            Rank_9: 90
+            Rank_10: 100
+        RetroMode:
+            Rank_1: 100
+            Rank_2: 200
+            Rank_3: 300
+            Rank_4: 400
+            Rank_5: 500
+            Rank_6: 600
+            Rank_7: 700
+            Rank_8: 800
+            Rank_9: 900
+            Rank_10: 1000
     Stab:
         Standard:
             Rank_1: 75
@@ -410,6 +479,29 @@ Swords:
         RetroMode:
             Rank_1: 100
 Unarmed:
+    UnarmedLimitBreak:
+        Standard:
+            Rank_1: 10
+            Rank_2: 20
+            Rank_3: 30
+            Rank_4: 40
+            Rank_5: 50
+            Rank_6: 60
+            Rank_7: 70
+            Rank_8: 80
+            Rank_9: 90
+            Rank_10: 100
+        RetroMode:
+            Rank_1: 100
+            Rank_2: 200
+            Rank_3: 300
+            Rank_4: 400
+            Rank_5: 500
+            Rank_6: 600
+            Rank_7: 700
+            Rank_8: 800
+            Rank_9: 900
+            Rank_10: 1000
     Berserk:
         Standard:
             Rank_1: 10