Browse Source

New skill 'Knock On Wood', changes to axe readying messages

nossr50 4 years ago
parent
commit
b31e1e533b

+ 10 - 0
Changelog.txt

@@ -1,4 +1,13 @@
 Version 2.1.156
 Version 2.1.156
+    Added Woodcutting skill 'Knock on Wood' - This ability gives you goodies (saplings, xp orbs, apples, etc) when using Tree Feller
+    Tree Feller no longer gives non-wood items by default, it now requires Knock on Wood for additional loot
+    Added new permission node 'mcmmo.ability.woodcutting.knockonwood'
+    Added new locale line 'Woodcutting.SubSkill.KnockOnWood.Name'
+    Added new locale line 'Woodcutting.SubSkill.KnockOnWood.Stat'
+    Added new locale line 'Woodcutting.SubSkill.KnockOnWood.Description'
+    Added new locale line 'Woodcutting.SubSkill.KnockOnWood.Loot.Normal'
+    Added new locale line 'Woodcutting.SubSkill.KnockOnWood.Loot.Rank2'
+    When you raise your axe you will now see information about any super abilities on CD
     Fixed a bug where Green Thumb would replant blocks floating in the air
     Fixed a bug where Green Thumb would replant blocks floating in the air
     Fixed a bug where the admin and party chat toggles in chat.yml didn't function as intended
     Fixed a bug where the admin and party chat toggles in chat.yml didn't function as intended
     * Fixed a bug where Master Angler rank 1 level requirement was set too high (default configs)
     * Fixed a bug where Master Angler rank 1 level requirement was set too high (default configs)
@@ -8,6 +17,7 @@ Version 2.1.156
     Removed incorrect translations of Master Angler from various locales
     Removed incorrect translations of Master Angler from various locales
     Modified Master Angler stat lines in /fishing
     Modified Master Angler stat lines in /fishing
     Updated Green Thumb description to mention that it needs a hoe
     Updated Green Thumb description to mention that it needs a hoe
+    'Abilities.Limits.Tree_Feller_Threshold' in config.yml now defaults to 1000 instead of 500
 
 
     NOTES:
     NOTES:
     You don't need to touch your config files, this update handles everything automagically.
     You don't need to touch your config files, this update handles everything automagically.

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

@@ -22,6 +22,7 @@ public class WoodcuttingCommand extends SkillCommand {
     private boolean canTreeFell;
     private boolean canTreeFell;
     private boolean canLeafBlow;
     private boolean canLeafBlow;
     private boolean canDoubleDrop;
     private boolean canDoubleDrop;
+    private boolean canKnockOnWood;
     private boolean canSplinter;
     private boolean canSplinter;
     private boolean canBarkSurgeon;
     private boolean canBarkSurgeon;
     private boolean canNaturesBounty;
     private boolean canNaturesBounty;
@@ -56,6 +57,7 @@ public class WoodcuttingCommand extends SkillCommand {
         canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(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;
         canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1;
         canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER);
         canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER);
+        canKnockOnWood = canTreeFell && canUseSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD);
         /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER);
         /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER);
         canBarkSurgeon = canUseSubskill(player, SubSkillType.WOODCUTTING_BARK_SURGEON);
         canBarkSurgeon = canUseSubskill(player, SubSkillType.WOODCUTTING_BARK_SURGEON);
         canNaturesBounty = canUseSubskill(player, SubSkillType.WOODCUTTING_NATURES_BOUNTY);*/
         canNaturesBounty = canUseSubskill(player, SubSkillType.WOODCUTTING_NATURES_BOUNTY);*/
@@ -69,6 +71,18 @@ public class WoodcuttingCommand extends SkillCommand {
             messages.add(getStatMessage(SubSkillType.WOODCUTTING_HARVEST_LUMBER, doubleDropChance)
             messages.add(getStatMessage(SubSkillType.WOODCUTTING_HARVEST_LUMBER, doubleDropChance)
                     + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
                     + (isLucky ? LocaleLoader.getString("Perks.Lucky.Bonus", doubleDropChanceLucky) : ""));
         }
         }
+
+        if (canKnockOnWood) {
+            String lootNote;
+
+            if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
+                lootNote = LocaleLoader.getString("Woodcutting.SubSkill.KnockOnWood.Loot.Rank2");
+            } else {
+                lootNote = LocaleLoader.getString("Woodcutting.SubSkill.KnockOnWood.Loot.Normal");
+            }
+
+            messages.add(getStatMessage(SubSkillType.WOODCUTTING_KNOCK_ON_WOOD, lootNote));
+        }
         
         
         if (canLeafBlow) {
         if (canLeafBlow) {
             messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1")));
             messages.add(LocaleLoader.getString("Ability.Generic.Template", LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1")));

+ 1 - 1
src/main/java/com/gmail/nossr50/config/Config.java

@@ -450,7 +450,7 @@ public class Config extends AutoUpdateConfigLoader {
     public int getAbilityToolDamage() { return config.getInt("Abilities.Tools.Durability_Loss", 1); }
     public int getAbilityToolDamage() { return config.getInt("Abilities.Tools.Durability_Loss", 1); }
 
 
     /* Thresholds */
     /* Thresholds */
-    public int getTreeFellerThreshold() { return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 500); }
+    public int getTreeFellerThreshold() { return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 1000); }
 
 
     /*
     /*
      * SKILL SETTINGS
      * SKILL SETTINGS

+ 64 - 2
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -14,8 +14,10 @@ import com.gmail.nossr50.datatypes.mods.CustomTool;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.PartyTeleportRecord;
 import com.gmail.nossr50.datatypes.party.PartyTeleportRecord;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
 import com.gmail.nossr50.datatypes.skills.ToolType;
 import com.gmail.nossr50.datatypes.skills.ToolType;
+import com.gmail.nossr50.datatypes.skills.subskills.interfaces.SubSkill;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.party.PartyManager;
 import com.gmail.nossr50.party.PartyManager;
@@ -40,6 +42,7 @@ import com.gmail.nossr50.skills.swords.SwordsManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.taming.TamingManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.unarmed.UnarmedManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
 import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager;
+import com.gmail.nossr50.util.BlockUtils;
 import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.EventUtils;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Permissions;
@@ -57,6 +60,7 @@ import net.kyori.adventure.identity.Identity;
 import org.apache.commons.lang.Validate;
 import org.apache.commons.lang.Validate;
 import org.bukkit.GameMode;
 import org.bukkit.GameMode;
 import org.bukkit.Location;
 import org.bukkit.Location;
+import org.bukkit.block.Block;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.metadata.FixedMetadataValue;
 import org.bukkit.metadata.FixedMetadataValue;
@@ -918,14 +922,25 @@ public class McMMOPlayer implements Identified {
             if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) {
             if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) {
                 int timeRemaining = calculateTimeRemaining(ability);
                 int timeRemaining = calculateTimeRemaining(ability);
 
 
-                if (!getAbilityMode(ability) && timeRemaining > 0) {
+                if (isAbilityOnCooldown(ability)) {
                     NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
                     NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining));
                     return;
                     return;
                 }
                 }
             }
             }
 
 
             if (Config.getInstance().getAbilityMessagesEnabled()) {
             if (Config.getInstance().getAbilityMessagesEnabled()) {
-                NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, tool.getRaiseTool());
+                /*
+                 *
+                 * IF THE TOOL IS AN AXE
+                 *
+                 */
+                if(tool == ToolType.AXE) {
+                    processAxeToolMessages();
+                } else {
+                    NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, tool.getRaiseTool());
+                }
+
+                //Send Sound
                 SoundManager.sendSound(player, player.getLocation(), SoundType.TOOL_READY);
                 SoundManager.sendSound(player, player.getLocation(), SoundType.TOOL_READY);
             }
             }
 
 
@@ -934,6 +949,53 @@ public class McMMOPlayer implements Identified {
         }
         }
     }
     }
 
 
+    public void processAxeToolMessages() {
+        Block rayCast = player.getTargetBlock(null, 100);
+
+        /*
+         * IF BOTH TREE FELLER & SKULL SPLITTER ARE ON CD
+         */
+        if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER) && isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) {
+            tooTiredMultiple(PrimarySkillType.WOODCUTTING, SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER, SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER);
+        /*
+         * IF TREE FELLER IS ON CD
+         * AND PLAYER IS LOOKING AT TREE
+         */
+        } else if(isAbilityOnCooldown(SuperAbilityType.TREE_FELLER)
+                && BlockUtils.isPartOfTree(rayCast)) {
+            raiseToolWithCooldowns(SubSkillType.WOODCUTTING_TREE_FELLER, SuperAbilityType.TREE_FELLER);
+
+        /*
+         * IF SKULL SPLITTER IS ON CD
+         */
+        } else if(isAbilityOnCooldown(SuperAbilityType.SKULL_SPLITTER)) {
+            raiseToolWithCooldowns(SubSkillType.AXES_SKULL_SPLITTER, SuperAbilityType.SKULL_SPLITTER);
+        } else {
+            NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, ToolType.AXE.getRaiseTool());
+        }
+    }
+
+    private void tooTiredMultiple(PrimarySkillType primarySkillType, SubSkillType aSubSkill, SuperAbilityType aSuperAbility, SubSkillType bSubSkill, SuperAbilityType bSuperAbility) {
+        String aSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", aSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(aSuperAbility)));
+        String bSuperAbilityCD = LocaleLoader.getString("Skills.TooTired.Named", bSubSkill.getLocaleName(), String.valueOf(calculateTimeRemaining(bSuperAbility)));
+        String allCDStr = aSuperAbilityCD + ", " + bSuperAbilityCD;
+
+        NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Skills.TooTired.Extra",
+                primarySkillType.getName(),
+                allCDStr);
+    }
+
+    private void raiseToolWithCooldowns(SubSkillType subSkillType, SuperAbilityType superAbilityType) {
+        NotificationManager.sendPlayerInformation(player, NotificationType.TOOL,
+                "Axes.Ability.Ready.Extra",
+                subSkillType.getLocaleName(),
+                String.valueOf(calculateTimeRemaining(superAbilityType)));
+    }
+
+    public boolean isAbilityOnCooldown(SuperAbilityType ability) {
+        return !getAbilityMode(ability) && calculateTimeRemaining(ability) > 0;
+    }
+
     /**
     /**
      * Calculate the time remaining until the ability's cooldown expires.
      * Calculate the time remaining until the ability's cooldown expires.
      *
      *

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

@@ -63,7 +63,7 @@ public enum PrimarySkillType {
     UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS,
     UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS,
             ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_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_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)),
     WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE,
     WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE,
-            ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER));
+            ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD));
 
 
     private final Class<? extends SkillManager> managerClass;
     private final Class<? extends SkillManager> managerClass;
     private final Color skillColor;
     private final Color skillColor;

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

@@ -101,6 +101,7 @@ public enum SubSkillType {
 
 
     /* Woodcutting */
     /* Woodcutting */
 /*    WOODCUTTING_BARK_SURGEON(3),*/
 /*    WOODCUTTING_BARK_SURGEON(3),*/
+    WOODCUTTING_KNOCK_ON_WOOD(2),
     WOODCUTTING_HARVEST_LUMBER(1),
     WOODCUTTING_HARVEST_LUMBER(1),
     WOODCUTTING_LEAF_BLOWER(1),
     WOODCUTTING_LEAF_BLOWER(1),
 /*    WOODCUTTING_NATURES_BOUNTY(3),
 /*    WOODCUTTING_NATURES_BOUNTY(3),

+ 1 - 4
src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java

@@ -15,8 +15,6 @@ import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Location;
 import org.bukkit.Location;
 import org.bukkit.block.BlockState;
 import org.bukkit.block.BlockState;
-import org.bukkit.entity.EntityType;
-import org.bukkit.entity.ExperienceOrb;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 
 
 import java.util.List;
 import java.util.List;
@@ -47,8 +45,7 @@ public class ExcavationManager extends SkillManager {
 
 
                         //Spawn Vanilla XP orbs if a dice roll succeeds
                         //Spawn Vanilla XP orbs if a dice roll succeeds
                         if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) {
                         if(RandomChanceUtil.rollDice(getArchaelogyExperienceOrbChance(), 100)) {
-                            ExperienceOrb experienceOrb = (ExperienceOrb) getPlayer().getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
-                            experienceOrb.setExperience(getExperienceOrbsReward());
+                            Misc.spawnExperienceOrb(location, getExperienceOrbsReward());
                         }
                         }
 
 
                         xp += treasure.getXp();
                         xp += treasure.getXp();

+ 14 - 2
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java

@@ -301,8 +301,20 @@ public class WoodcuttingManager extends SkillManager {
                 processHarvestLumber(blockState);
                 processHarvestLumber(blockState);
             } else if (BlockUtils.isNonWoodPartOfTree(blockState)) {
             } else if (BlockUtils.isNonWoodPartOfTree(blockState)) {
                 //Drop displaced non-woodcutting XP blocks
                 //Drop displaced non-woodcutting XP blocks
-//                Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1);
-                Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK);
+
+                if(RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
+                    Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK);
+
+                    if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) {
+                        if(RandomChanceUtil.rollDice(75, 100)) {
+                            int randOrbCount = Math.max(1, Misc.getRandom().nextInt(50));
+                            Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount);
+                        }
+                    }
+
+                } else {
+                    Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK, 1);
+                }
             }
             }
 
 
             blockState.setType(Material.AIR);
             blockState.setType(Material.AIR);

+ 9 - 0
src/main/java/com/gmail/nossr50/util/BlockUtils.java

@@ -11,6 +11,7 @@ import com.gmail.nossr50.skills.salvage.Salvage;
 import com.gmail.nossr50.util.random.RandomChanceSkill;
 import com.gmail.nossr50.util.random.RandomChanceSkill;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.random.RandomChanceUtil;
 import org.bukkit.Material;
 import org.bukkit.Material;
+import org.bukkit.block.Block;
 import org.bukkit.block.BlockState;
 import org.bukkit.block.BlockState;
 import org.bukkit.block.data.Ageable;
 import org.bukkit.block.data.Ageable;
 import org.bukkit.block.data.BlockData;
 import org.bukkit.block.data.BlockData;
@@ -179,6 +180,10 @@ public final class BlockUtils {
         return mcMMO.getMaterialMapStore().isTreeFellerDestructible(blockState.getType());
         return mcMMO.getMaterialMapStore().isTreeFellerDestructible(blockState.getType());
     }
     }
 
 
+    public static boolean isNonWoodPartOfTree(Material material) {
+        return mcMMO.getMaterialMapStore().isTreeFellerDestructible(material);
+    }
+
     /**
     /**
      * Determine if a given block should be affected by Flux Mining
      * Determine if a given block should be affected by Flux Mining
      *
      *
@@ -274,4 +279,8 @@ public final class BlockUtils {
         }
         }
         return true;
         return true;
     }
     }
+
+    public static boolean isPartOfTree(Block rayCast) {
+        return hasWoodcuttingXP(rayCast.getState()) || isNonWoodPartOfTree(rayCast.getType());
+    }
 }
 }

+ 34 - 0
src/main/java/com/gmail/nossr50/util/Misc.java

@@ -12,6 +12,7 @@ import org.bukkit.Material;
 import org.bukkit.block.BlockState;
 import org.bukkit.block.BlockState;
 import org.bukkit.entity.*;
 import org.bukkit.entity.*;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.ItemStack;
+import org.bukkit.scheduler.BukkitRunnable;
 import org.bukkit.util.Vector;
 import org.bukkit.util.Vector;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.Nullable;
@@ -310,4 +311,37 @@ public final class Misc {
     public static boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) {
     public static boolean isPartyLeader(@NotNull McMMOPlayer mmoPlayer) {
         return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId());
         return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId());
     }
     }
+
+//    public static void spawnExperienceOrb(@NotNull Location location, int orbAmount, int experienceValue) {
+//        for (int i = 0; i < orbAmount; i++) {
+//            new SpawnOrbTask(location, experienceValue).runTaskLater(mcMMO.p, 20);
+//        }
+//    }
+
+    public static void spawnExperienceOrb(@NotNull Location location, int experienceValue) {
+        if(location.getWorld() == null)
+            return;
+
+        ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
+        experienceOrb.setExperience(experienceValue);
+    }
+
+    private static class SpawnOrbTask extends BukkitRunnable {
+        private final Location location;
+        private int orbExpValue;
+
+        private SpawnOrbTask(Location location, int orbExpValue) {
+            this.location = location;
+            this.orbExpValue = orbExpValue;
+        }
+
+        @Override
+        public void run() {
+            if(location == null || location.getWorld() == null)
+                return;
+
+            ExperienceOrb experienceOrb = (ExperienceOrb) location.getWorld().spawnEntity(location, EntityType.EXPERIENCE_ORB);
+            experienceOrb.setExperience(orbExpValue);
+        }
+    }
 }
 }

+ 1 - 1
src/main/resources/config.yml

@@ -303,7 +303,7 @@ Abilities:
         Super_Breaker: 0
         Super_Breaker: 0
         Tree_Feller: 0
         Tree_Feller: 0
     Limits:
     Limits:
-        Tree_Feller_Threshold: 500
+        Tree_Feller_Threshold: 1000
     Tools:
     Tools:
         # Use more tool durability while using abilities. Set Durability_Loss to 0 to disable the extra durability damage.
         # Use more tool durability while using abilities. Set Durability_Loss to 0 to disable the extra durability damage.
         Durability_Loss: 1
         Durability_Loss: 1

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

@@ -184,6 +184,7 @@ Axes.Ability.Bonus.4=Greater Impact
 Axes.Ability.Bonus.5=Deal {0} Bonus DMG to unarmored foes
 Axes.Ability.Bonus.5=Deal {0} Bonus DMG to unarmored foes
 Axes.Ability.Lower=&7You lower your Axe.
 Axes.Ability.Lower=&7You lower your Axe.
 Axes.Ability.Ready=&3You &6ready&3 your Axe.
 Axes.Ability.Ready=&3You &6ready&3 your Axe.
+Axes.Ability.Ready.Extra=&3You &6ready&3 your Axe. [[GRAY]]({0} is on cooldown for {1}s)
 Axes.Combat.CritStruck=&4You were CRITICALLY hit!
 Axes.Combat.CritStruck=&4You were CRITICALLY hit!
 Axes.Combat.CriticalHit=CRITICAL HIT!
 Axes.Combat.CriticalHit=CRITICAL HIT!
 Axes.Combat.GI.Proc=&a**STRUCK WITH GREAT FORCE**
 Axes.Combat.GI.Proc=&a**STRUCK WITH GREAT FORCE**
@@ -531,6 +532,11 @@ Woodcutting.SubSkill.TreeFeller.Description=Make trees explode
 Woodcutting.SubSkill.TreeFeller.Stat=Tree Feller Length
 Woodcutting.SubSkill.TreeFeller.Stat=Tree Feller Length
 Woodcutting.SubSkill.LeafBlower.Name=Leaf Blower
 Woodcutting.SubSkill.LeafBlower.Name=Leaf Blower
 Woodcutting.SubSkill.LeafBlower.Description=Blow Away Leaves
 Woodcutting.SubSkill.LeafBlower.Description=Blow Away Leaves
+Woodcutting.SubSkill.KnockOnWood.Name=Knock On Wood
+Woodcutting.SubSkill.KnockOnWood.Description=Find additional goodies when using Tree Feller
+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.Name=Harvest Lumber
 Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract more Lumber
 Woodcutting.SubSkill.HarvestLumber.Description=Skillfully extract more Lumber
 Woodcutting.SubSkill.HarvestLumber.Stat=Double Drop Chance
 Woodcutting.SubSkill.HarvestLumber.Stat=Double Drop Chance
@@ -989,6 +995,8 @@ Skills.Stats={0}&a{1}&3 XP(&7{2}&3/&7{3}&3)
 Skills.ChildStats={0}&a{1}
 Skills.ChildStats={0}&a{1}
 Skills.MaxXP=Max
 Skills.MaxXP=Max
 Skills.TooTired=You are too tired to use that ability again. &e({0}s)
 Skills.TooTired=You are too tired to use that ability again. &e({0}s)
+Skills.TooTired.Named=[[GRAY]](&6{0}&e {1}s[[GRAY]])
+Skills.TooTired.Extra=&6{0} &eSuper Ability CDs - {1}
 Skills.Cancelled=&6{0} &ccancelled!
 Skills.Cancelled=&6{0} &ccancelled!
 Skills.ConfirmOrCancel=&aRight-click again to confirm &6{0}&a. Left-click to cancel.
 Skills.ConfirmOrCancel=&aRight-click again to confirm &6{0}&a. Left-click to cancel.
 Skills.AbilityGateRequirementFail=&7You require &e{0}&7 more levels of &3{1}&7 to use this super ability.
 Skills.AbilityGateRequirementFail=&7You require &e{0}&7 more levels of &3{1}&7 to use this super ability.

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

@@ -695,8 +695,11 @@ permissions:
             mcmmo.ability.woodcutting.splinter: true
             mcmmo.ability.woodcutting.splinter: true
             mcmmo.ability.woodcutting.barksurgeon: true
             mcmmo.ability.woodcutting.barksurgeon: true
             mcmmo.ability.woodcutting.naturesbounty: true
             mcmmo.ability.woodcutting.naturesbounty: true
+            mcmmo.ability.woodcutting.knockonwood: true
             mcmmo.ability.woodcutting.leafblower: true
             mcmmo.ability.woodcutting.leafblower: true
             mcmmo.ability.woodcutting.treefeller: true
             mcmmo.ability.woodcutting.treefeller: true
+    mcmmo.ability.woodcutting.knockonwood:
+        description: Allows access to Knock on Wood subskill
     mcmmo.ability.woodcutting.splinter:
     mcmmo.ability.woodcutting.splinter:
         description: Allows access to Splinter
         description: Allows access to Splinter
     mcmmo.ability.woodcutting.barksurgeon:
     mcmmo.ability.woodcutting.barksurgeon:

+ 6 - 26
src/main/resources/skillranks.yml

@@ -605,15 +605,6 @@ Unarmed:
             Rank_20: 1000
             Rank_20: 1000
 
 
 Woodcutting:
 Woodcutting:
-    Splinter:
-        Standard:
-            Rank_1: 5
-            Rank_2: 30
-            Rank_3: 55
-        RetroMode:
-            Rank_1: 50
-            Rank_2: 300
-            Rank_3: 550
     TreeFeller:
     TreeFeller:
         Standard:
         Standard:
             Rank_1: 5
             Rank_1: 5
@@ -627,29 +618,18 @@ Woodcutting:
             Rank_3: 500
             Rank_3: 500
             Rank_4: 750
             Rank_4: 750
             Rank_5: 1000
             Rank_5: 1000
-    BarkSurgeon:
+    HarvestLumber:
         Standard:
         Standard:
-            Rank_1: 70
-            Rank_2: 80
-            Rank_3: 95
+            Rank_1: 1
         RetroMode:
         RetroMode:
-            Rank_1: 700
-            Rank_2: 800
-            Rank_3: 950
-    NaturesBounty:
+            Rank_1: 1
+    KnockOnWood:
         Standard:
         Standard:
-            Rank_1: 40
+            Rank_1: 30
             Rank_2: 60
             Rank_2: 60
-            Rank_3: 90
         RetroMode:
         RetroMode:
-            Rank_1: 400
+            Rank_1: 300
             Rank_2: 600
             Rank_2: 600
-            Rank_3: 900
-    HarvestLumber:
-        Standard:
-            Rank_1: 1
-        RetroMode:
-            Rank_1: 1
     LeafBlower:
     LeafBlower:
         Standard:
         Standard:
             Rank_1: 15
             Rank_1: 15