Переглянути джерело

More work on Woodcutting and Tree Feller

bm01 12 роки тому
батько
коміт
1bbb245e32

+ 12 - 11
src/main/java/com/gmail/nossr50/listeners/BlockListener.java

@@ -177,17 +177,18 @@ public class BlockListener implements Listener {
 
         /* WOOD CUTTING */
         else if (BlockChecks.isLog(block) && Permissions.woodcutting(player)) {
-            if (configInstance.getWoodcuttingRequiresTool()) {
-                if (ItemChecks.isAxe(inHand)) {
-                    Woodcutting.woodcuttingBlockCheck(player, block);
-                }
+            if (!mcMMO.placeStore.isTrue(block) && profile.getAbilityMode(AbilityType.TREE_FELLER) && Permissions.treeFeller(player) && ItemChecks.isAxe(inHand)) {
+                Woodcutting.beginTreeFeller(event);
             }
             else {
-                Woodcutting.woodcuttingBlockCheck(player, block);
-            }
-
-            if (!mcMMO.placeStore.isTrue(block) && profile.getAbilityMode(AbilityType.TREE_FELLER) && Permissions.treeFeller(player) && ItemChecks.isAxe(inHand)) {
-                Woodcutting.treeFeller(event);
+                if (configInstance.getWoodcuttingRequiresTool()) {
+                    if (ItemChecks.isAxe(inHand)) {
+                        Woodcutting.beginWoodcutting(player, block);
+                    }
+                }
+                else {
+                    Woodcutting.beginWoodcutting(player, block);
+                }
             }
         }
 
@@ -318,12 +319,12 @@ public class BlockListener implements Listener {
                 if (configInstance.getWoodcuttingRequiresTool()) {
                     if (ItemChecks.isAxe(inHand)) {
                         event.setInstaBreak(true);
-                        Woodcutting.leafBlower(player, block);
+                        Woodcutting.beginLeafBlower(player, block);
                     }
                 }
                 else if (!inHand.getType().equals(Material.SHEARS)) {
                     event.setInstaBreak(true);
-                    Woodcutting.leafBlower(player, block);
+                    Woodcutting.beginLeafBlower(player, block);
                 }
             }
         }

+ 235 - 0
src/main/java/com/gmail/nossr50/skills/woodcutting/TreeFeller.java

@@ -0,0 +1,235 @@
+package com.gmail.nossr50.skills.woodcutting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.inventory.ItemStack;
+
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.mods.CustomBlock;
+import com.gmail.nossr50.locale.LocaleLoader;
+import com.gmail.nossr50.skills.Combat;
+import com.gmail.nossr50.skills.SkillType;
+import com.gmail.nossr50.skills.Skills;
+import com.gmail.nossr50.util.BlockChecks;
+import com.gmail.nossr50.util.Misc;
+import com.gmail.nossr50.util.ModChecks;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.Users;
+
+public abstract class TreeFeller {
+    private static boolean treeFellerReachedThreshold = false;
+
+    /**
+     * Handle the Tree Feller ability.
+     *
+     * @param event Event to process
+     */
+    public static void process(BlockBreakEvent event) {
+        List<Block> treeFellerBlocks = new ArrayList<Block>();
+        Player player = event.getPlayer();
+
+        processRecursively(event.getBlock(), treeFellerBlocks);
+
+        // If the player is trying to break to many block
+        if (treeFellerReachedThreshold) {
+            treeFellerReachedThreshold = false;
+
+            player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFellerThreshold"));
+            return;
+        }
+
+        // If the tool can't sustain the durability loss
+        if (!handleDurabilityLoss(treeFellerBlocks, player)) {
+            player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFeller.Splinter"));
+
+            int health = player.getHealth();
+
+            if (health > 1) {
+                Combat.dealDamage(player, Misc.getRandom().nextInt(health - 1));
+            }
+
+            return;
+        }
+
+        removeBlocks(treeFellerBlocks, player);
+    }
+
+    /**
+     * Process Tree Feller
+     *
+     * @param block Point of origin of the layer
+     * @param treeFellerBlocks List of blocks to be removed
+     */
+    private static void processRecursively(Block block, List<Block> treeFellerBlocks) {
+        List<Block> futureCenterBlocks = new ArrayList<Block>();
+        boolean centerIsLog = (block.getType() == Material.LOG || (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)));
+        Block nextBlock = block.getRelative(BlockFace.UP);;
+
+        // Handle the block above 'block'
+        if (addBlock(nextBlock, treeFellerBlocks)) {
+            if (treeFellerReachedThreshold) {
+                return;
+            }
+
+            if (centerIsLog) {
+                futureCenterBlocks.add(nextBlock);
+            }
+        }
+
+        World world = block.getWorld();
+
+        // Handle the blocks around 'block'
+        for (int x = -1 ; x <= 1 ; x++) {
+            for (int z = -1 ; z <= 1 ; z++) {
+                nextBlock = world.getBlockAt(block.getLocation().add(x, 0, z));
+
+                if (addBlock(nextBlock, treeFellerBlocks)) {
+                    if (treeFellerReachedThreshold) {
+                        return;
+                    }
+
+                    if (centerIsLog) {
+                        futureCenterBlocks.add(nextBlock);
+                    }
+                }
+            }
+        }
+
+        // Recursive call for each log found
+        for (Block futurCenterBlock : futureCenterBlocks) {
+            if (treeFellerReachedThreshold) {
+                return;
+            }
+
+            processRecursively(futurCenterBlock, treeFellerBlocks);
+        }
+    }
+
+    /**
+     * Add a block to the block list
+     *
+     * @param block Block to be added
+     * @param treeFellerBlocks List of blocks to be removed
+     * @return True if block was added
+     */
+    private static boolean addBlock(Block block, List<Block> treeFellerBlocks) {
+        if (BlockChecks.treeFellerCompatible(block) && !treeFellerBlocks.contains(block) && !mcMMO.placeStore.isTrue(block)) {
+            treeFellerBlocks.add(block);
+
+            if (treeFellerBlocks.size() >= Config.getInstance().getTreeFellerThreshold()) {
+                treeFellerReachedThreshold = true;
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Handle the durability loss
+     *
+     * @param treeFellerBlocks List of blocks to be removed
+     * @param Player Player using the ability
+     * @return True if the tool can sustain the durability loss
+     */
+    private static boolean handleDurabilityLoss(List<Block> treeFellerBlocks, Player player) {
+        ItemStack inHand = player.getItemInHand();
+        Material inHandMaterial = inHand.getType();
+
+        if (inHandMaterial != Material.AIR) {
+            boolean blockModsEnabled = Config.getInstance().getBlockModsEnabled();
+            short durabilityLoss = 0;
+
+            for (Block block : treeFellerBlocks) {
+                if (block.getType() == Material.LOG || (blockModsEnabled && ModChecks.isCustomLogBlock(block))) {
+                    durabilityLoss += Misc.toolDurabilityLoss;
+                }
+            }
+
+            short finalDurability = (short) (inHand.getDurability() + durabilityLoss);
+            short maxDurability = ModChecks.isCustomTool(inHand) ? ModChecks.getToolFromItemStack(inHand).getDurability() : inHandMaterial.getMaxDurability();
+
+            if (finalDurability >= maxDurability) {
+                inHand.setDurability(maxDurability);
+                return false;
+            }
+    
+            inHand.setDurability(finalDurability);
+        }
+
+        return true;
+    }
+
+    /**
+     * Handles removing & dropping the blocks
+     *
+     * @param treeFellerBlocks List of blocks to be removed
+     * @param player Player using the ability
+     */
+    private static void removeBlocks(List<Block> treeFellerBlocks, Player player) {
+        int xp = 0;
+
+        for (Block block : treeFellerBlocks) {
+            if (!Misc.blockBreakSimulate(block, player, true)) {
+                break; // TODO: Shouldn't we use continue instead?
+            }
+
+            switch (block.getType()) {
+            case LOG:
+                Woodcutting.checkDoubleDrop(player, block);
+
+                byte extraData = block.getData();
+                xp += Woodcutting.getExperienceFromLog(block);
+                // TODO: Nerf XP from jungle trees, as it was done previously
+
+                Misc.dropItem(block.getLocation(), new ItemStack(Material.LOG, 1, extraData));
+                break;
+            case LEAVES:
+                Misc.randomDropItem(block.getLocation(), new ItemStack(Material.LOG, 1, (short) (block.getData() & 3)), 10);
+                break;
+            default:
+                if (ModChecks.isCustomLogBlock(block)) {
+                    Woodcutting.checkDoubleDrop(player, block);
+
+                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
+                    xp = customBlock.getXpGain();
+                    int minimumDropAmount = customBlock.getMinimumDropAmount();
+                    int maximumDropAmount = customBlock.getMaximumDropAmount();
+                    Location location = block.getLocation();
+                    ItemStack item = customBlock.getItemDrop();;
+
+                    Misc.dropItems(location, item, minimumDropAmount);
+
+                    if (minimumDropAmount < maximumDropAmount) {
+                        Misc.randomDropItems(location, item, 50, maximumDropAmount - minimumDropAmount);
+                    }
+                }
+                else if (ModChecks.isCustomLeafBlock(block)) {
+                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
+
+                    Misc.randomDropItem(block.getLocation(), customBlock.getItemDrop(), 10);
+                }
+
+                break;
+            }
+
+            block.setData((byte) 0);
+            block.setType(Material.AIR);
+        }
+
+        // Do we really have to check the permission here?
+        if (Permissions.woodcutting(player)) {
+            Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp);
+        }
+    }
+}

+ 84 - 326
src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java

@@ -1,19 +1,12 @@
 package com.gmail.nossr50.skills.woodcutting;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.TreeSpecies;
-import org.bukkit.World;
 import org.bukkit.block.Block;
-import org.bukkit.block.BlockFace;
 import org.bukkit.entity.Player;
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.inventory.ItemStack;
-import org.bukkit.material.MaterialData;
-import org.bukkit.material.Tree;
 import org.getspout.spoutapi.sound.SoundEffect;
 
 import com.gmail.nossr50.mcMMO;
@@ -21,397 +14,162 @@ import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.mods.CustomBlock;
 import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
-import com.gmail.nossr50.locale.LocaleLoader;
-import com.gmail.nossr50.skills.Combat;
 import com.gmail.nossr50.skills.SkillType;
 import com.gmail.nossr50.skills.Skills;
 import com.gmail.nossr50.spout.SpoutSounds;
-import com.gmail.nossr50.util.BlockChecks;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.ModChecks;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.Users;
 
 public class Woodcutting {
-    private static final AdvancedConfig ADVANCED_CONFIG = AdvancedConfig.getInstance();
-    private static boolean treeFellerReachedThreshold = false;
-
-    public static int doubleDropsMaxLevel = ADVANCED_CONFIG.getMiningDoubleDropMaxLevel();
-    public static double doubleDropsMaxChance = ADVANCED_CONFIG.getMiningDoubleDropChance();
-    public static boolean doubleDropsDisabled = Config.getInstance().woodcuttingDoubleDropsDisabled();
-
-    public static int leafBlowerUnlockLevel = ADVANCED_CONFIG.getLeafBlowUnlockLevel();
+    public static final int DOUBLE_DROP_MAX_LEVEL = AdvancedConfig.getInstance().getMiningDoubleDropMaxLevel();
+    public static final double DOUBLE_DROP_CHANCE = AdvancedConfig.getInstance().getMiningDoubleDropChance();
+    public static final int LEAF_BLOWER_UNLOCK_LEVEL = AdvancedConfig.getInstance().getLeafBlowUnlockLevel();
+    public static final boolean DOUBLE_DROP_DISABLED = Config.getInstance().woodcuttingDoubleDropsDisabled();
 
     /**
-     * Handle the Tree Feller ability.
+     * Begin Tree Feller ability
      *
      * @param event Event to process
      */
-    public static void treeFeller(BlockBreakEvent event) {
-        List<Block> toBeFelled = processTreeFeller(event);
-
-        if (toBeFelled != null && !toBeFelled.isEmpty()) {
-            removeBlocks(toBeFelled, event.getPlayer());
-        }
+    public static void beginTreeFeller(BlockBreakEvent event) {
+        TreeFeller.process(event);
     }
 
     /**
-     * Handles removing & dropping the blocks from Tree Feller.
+     * Begin Leaf Blower ability.
      *
-     * @param toBeFelled List of blocks to be removed
      * @param player Player using the ability
+     * @param block Block being broken
      */
-    private static void removeBlocks(List<Block> toBeFelled, Player player) {
-        ItemStack inHand = player.getItemInHand();
-        Material inHandMaterial = inHand.getType();
-        short finalDurability = (short) (inHand.getDurability() + calulateDurabilityLossFromTreeFeller(toBeFelled));
-
-        // Prevent the tree to be cut down if the tool doesn't have enough durability
-        if (inHandMaterial != Material.AIR) {
-            short maxDurability = ModChecks.isCustomTool(inHand) ? ModChecks.getToolFromItemStack(inHand).getDurability() : inHandMaterial.getMaxDurability();
-
-            if (finalDurability >= maxDurability) {
-                player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFeller.Splinter"));
-
-                int health = player.getHealth();
-
-                if (health >= 2) {
-                    Combat.dealDamage(player, Misc.getRandom().nextInt(health - 1)); // Why not base the damage on the number of elements in toBeFelled?
-                }
-
-                inHand.setDurability(maxDurability);
-                return;
-            }
-        }
-
-        inHand.setDurability(finalDurability);
-
-        int xp = 0;
-        ItemStack item = null;
-
-        for (Block block : toBeFelled) {
-            if (!Misc.blockBreakSimulate(block, player, true)) {
-                break;
-            }
-
-            if (block.getType() == Material.LOG) {
-                Woodcutting.woodCuttingProcCheck(player, block);
-
-                TreeSpecies species = ((Tree) block.getState().getData()).getSpecies();
-
-                switch (species) {
-                case GENERIC:
-                    item = new MaterialData(Material.LOG, TreeSpecies.GENERIC.getData()).toItemStack(1);
-                    xp += Config.getInstance().getWoodcuttingXPOak();
-                    break;
-                case REDWOOD:
-                    item = new MaterialData(Material.LOG, TreeSpecies.REDWOOD.getData()).toItemStack(1);
-                    xp += Config.getInstance().getWoodcuttingXPSpruce();
-                    break;
-                case BIRCH:
-                    item = new MaterialData(Material.LOG, TreeSpecies.BIRCH.getData()).toItemStack(1);
-                    xp += Config.getInstance().getWoodcuttingXPBirch();
-                    break;
-                case JUNGLE:
-                    item = new MaterialData(Material.LOG, TreeSpecies.JUNGLE.getData()).toItemStack(1);
-                    xp += Config.getInstance().getWoodcuttingXPJungle() / 2; // Nerf XP from Jungle Trees when using Tree Feller
-                    break;
-                default:
-                    break;
-                }
-
-                Misc.dropItem(block.getLocation(), item);
-            }
-            else if (block.getType() == Material.LEAVES) {
-                item = new MaterialData(Material.SAPLING, (byte) (block.getData() & 3)).toItemStack(1); 
-
-                Misc.randomDropItem(block.getLocation(), item, 10);
-            }
-            else if (Config.getInstance().getBlockModsEnabled()) {
-                if (ModChecks.isCustomLogBlock(block)) {
-                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
-
-                    Woodcutting.woodCuttingProcCheck(player, block);
-
-                    xp = customBlock.getXpGain();
-                    int minimumDropAmount = customBlock.getMinimumDropAmount();
-                    int maximumDropAmount = customBlock.getMaximumDropAmount();
-                    Location location = block.getLocation();
-                    item = customBlock.getItemDrop();
-
-                    Misc.dropItems(location, item, minimumDropAmount);
-
-                    if (minimumDropAmount < maximumDropAmount) {
-                        Misc.randomDropItems(location, item, 50, maximumDropAmount - minimumDropAmount);
-                    }
-                }
-                else if (ModChecks.isCustomLeafBlock(block)) {
-                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
-
-                    Misc.randomDropItem(block.getLocation(), customBlock.getItemDrop(), 10);
-                }
-            }
-
-            block.setData((byte) 0);
-            block.setType(Material.AIR);
-        }
+    public static void beginLeafBlower(Player player, Block block) {
+        mcMMO.p.getServer().getPluginManager().callEvent(new FakePlayerAnimationEvent(player));
 
-        if (Permissions.woodcutting(player)) {
-            Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp);
+        if (mcMMO.spoutEnabled) {
+            SpoutSounds.playSoundForPlayer(SoundEffect.POP, player, block.getLocation());
         }
     }
 
     /**
-     * Process Tree Feller around a block.
+     * Begin Woodcutting process
      *
-     * @param block Point of origin of the layer
-     * @param toBeFelled List of blocks to be removed
+     * @param player Player breaking the block
+     * @param block Block being broken
      */
-    private static void processTreeFellerAroundBlock(Block block, List<Block> toBeFelled) {
-        // TODO: too much duplicate code here
-        List<Block> futureCenterBlocks = new ArrayList<Block>();
-        boolean centerIsLog = (block.getType() == Material.LOG); //TODO: custom blocks?
-        
-        // Handle the block above 'block'
-        Block nextBlock = block.getRelative(BlockFace.UP);;
-
-        if (BlockChecks.treeFellerCompatible(nextBlock) && !toBeFelled.contains(nextBlock) && !mcMMO.placeStore.isTrue(nextBlock)) {
-            toBeFelled.add(nextBlock);
-
-            if (centerIsLog) {
-                futureCenterBlocks.add(nextBlock);
-            }
+    public static void beginWoodcutting(Player player, Block block) {
+        int xp = 0;
 
-            if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
-                treeFellerReachedThreshold = true;
-                return;
-            }
+        if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) {
+            xp = ModChecks.getCustomBlock(block).getXpGain();
         }
-
-        World world = block.getWorld();
-
-        // Handle the blocks around 'block'
-        for (int x = -1 ; x <= 1 ; x++) {
-            for (int z = -1 ; z <= 1 ; z++) {
-                nextBlock = world.getBlockAt(block.getLocation().add(x, 0, z));
-
-                if (BlockChecks.treeFellerCompatible(nextBlock) && !toBeFelled.contains(nextBlock) && !mcMMO.placeStore.isTrue(nextBlock)) {
-                    toBeFelled.add(nextBlock);
-
-                    if (centerIsLog) {
-                        futureCenterBlocks.add(nextBlock);
-                    }
-
-                    if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
-                        treeFellerReachedThreshold = true;
-                        return;
-                    }
-                }
+        else {
+            try {
+                xp = getExperienceFromLog(block);
             }
-        }
-
-        // Recursive call for each log found
-        for (Block futurCenterBlock : futureCenterBlocks) {
-            if (treeFellerReachedThreshold) {
+            catch (IllegalArgumentException exception) {
                 return;
             }
-
-            processTreeFellerAroundBlock(futurCenterBlock, toBeFelled);
         }
+
+        checkDoubleDrop(player, block);
+        Skills.xpProcessing(player,  Users.getProfile(player), SkillType.WOODCUTTING, xp);
     }
 
     /**
-     * Process Tree Feller.
+     * Retrieve the experience from a log
      *
-     * @param event Event to process
-     * @return List of blocks to be removed
+     * @param log Log being broken
+     * @return Amount of experience
+     * @throws IllegalArgumentException if 'log' is invalid
      */
-    private static List<Block> processTreeFeller(BlockBreakEvent event) {
-        List<Block> toBeFelled = new ArrayList<Block>();
-
-        processTreeFellerAroundBlock(event.getBlock(), toBeFelled);
-
-        if (treeFellerReachedThreshold) {
-            treeFellerReachedThreshold = false;
+    protected static int getExperienceFromLog(Block log) {
+        TreeSpecies logType = TreeSpecies.getByData(log.getData());
 
-            event.getPlayer().sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFellerThreshold"));
-            return null;
+        // Apparently species can be null in certain cases (custom server mods?)
+        // https://github.com/mcMMO-Dev/mcMMO/issues/229
+        if (logType == null) {
+            throw new IllegalArgumentException();
         }
 
-        return toBeFelled;
+        switch (logType) {
+        case GENERIC:
+            return Config.getInstance().getWoodcuttingXPOak();
+        case REDWOOD:
+            return Config.getInstance().getWoodcuttingXPSpruce();
+        case BIRCH:
+            return Config.getInstance().getWoodcuttingXPBirch();
+        case JUNGLE:
+            return Config.getInstance().getWoodcuttingXPJungle();
+        default:
+            throw new IllegalArgumentException();
+        }
     }
 
     /**
-     * Check for double drops.
+     * Check for double drops
      *
      * @param player Player breaking the block
      * @param block Block being broken
      */
-    private static void woodCuttingProcCheck(Player player, Block block) {
-        final double MAX_CHANCE = ADVANCED_CONFIG.getWoodcuttingDoubleDropChance();
-        final int MAX_BONUS_LEVEL = ADVANCED_CONFIG.getWoodcuttingDoubleDropMaxLevel();
-        byte type = block.getData();
-
-        if ((type & 0x4) == 0x4)
-            type ^= 0x4;
-
-        if ((type & 0x8) == 0x8)
-            type ^= 0x8;
-
-        Material blockMaterial = block.getType();
-        int chance = (int) ((MAX_CHANCE / MAX_BONUS_LEVEL) * Users.getProfile(player).getSkillLevel(SkillType.WOODCUTTING));
-        
-        if (chance > MAX_CHANCE) {
-            chance = (int) MAX_CHANCE;
+    protected static void checkDoubleDrop(Player player, Block block) {
+        if (!Permissions.woodcuttingDoubleDrops(player)) {
+            return;
         }
 
+        int chance = (int) ((DOUBLE_DROP_CHANCE / DOUBLE_DROP_MAX_LEVEL) * Users.getProfile(player).getSkillLevel(SkillType.WOODCUTTING));
         int activationChance = Misc.calculateActivationChance(Permissions.luckyWoodcutting(player));
 
-        if (chance > Misc.getRandom().nextInt(activationChance) && Permissions.woodcuttingDoubleDrops(player)) {
-            Config configInstance = Config.getInstance();
-            ItemStack item = null;
-            Location location = null;
-
-            if (configInstance.getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) {
-                CustomBlock customBlock = ModChecks.getCustomBlock(block);
-                int minimumDropAmount = customBlock.getMinimumDropAmount();
-                int maximumDropAmount = customBlock.getMaximumDropAmount();
-
-                item = customBlock.getItemDrop();
-                location = block.getLocation();
-
-                if (minimumDropAmount != maximumDropAmount) {
-                    Misc.dropItems(location, item, minimumDropAmount);
-                    Misc.randomDropItems(location, item, 50, maximumDropAmount - minimumDropAmount);
-                }
-                else {
-                    Misc.dropItems(location, item, minimumDropAmount);
-                }
-            }
-            else {
-                item = (new MaterialData(blockMaterial, type)).toItemStack(1);
-                location = block.getLocation();
-
-                switch (TreeSpecies.getByData(type)) {
-                case GENERIC:
-                    if (configInstance.getOakDoubleDropsEnabled()) {
-                        Misc.dropItem(location, item);
-                    }
-                    break;
-
-                case REDWOOD:
-                    if (configInstance.getSpruceDoubleDropsEnabled()) {
-                        Misc.dropItem(location, item);
-                    }
-                    break;
-
-                case BIRCH:
-                    if (configInstance.getBirchDoubleDropsEnabled()) {
-                        Misc.dropItem(location, item);
-                    }
-                    break;
-
-                case JUNGLE:
-                    if (configInstance.getJungleDoubleDropsEnabled()) {
-                        Misc.dropItem(location, item);
-                    }
-                    break;
-
-                default:
-                    break;
-                }
-            }
+        if (chance > DOUBLE_DROP_CHANCE) {
+            chance = (int) DOUBLE_DROP_CHANCE;
         }
-    }
 
-    /**
-     * Check XP gain for woodcutting.
-     *
-     * @param player Player breaking the block
-     * @param block Block being broken
-     */
-    public static void woodcuttingBlockCheck(Player player, Block block) {
-        if (mcMMO.placeStore.isTrue(block)) {
+        if (chance <= Misc.getRandom().nextInt(activationChance)) {
             return;
         }
 
-        int xp = 0;
-
         if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) {
-            xp = ModChecks.getCustomBlock(block).getXpGain();
-        }
-        else {
-            byte type = block.getData();
+            CustomBlock customBlock = ModChecks.getCustomBlock(block);
+            int minimumDropAmount = customBlock.getMinimumDropAmount();
+            int maximumDropAmount = customBlock.getMaximumDropAmount();
+            Location location = block.getLocation();
+            ItemStack item = customBlock.getItemDrop();
 
-            if ((type & 0x4) == 0x4)
-                type ^= 0x4;
+            Misc.dropItems(location, item, minimumDropAmount);
 
-            if ((type & 0x8) == 0x8)
-                type ^= 0x8;
-
-            TreeSpecies species = TreeSpecies.getByData(type);
-
-            // Apparently species can be null in certain cases (custom server mods?)
-            // https://github.com/mcMMO-Dev/mcMMO/issues/229
-            if (species == null)
-                return;
+            if (minimumDropAmount != maximumDropAmount) {
+                Misc.randomDropItems(location, item, 50, maximumDropAmount - minimumDropAmount);
+            }
+        }
+        else {
+            byte extraData = block.getData();
+            Location location = block.getLocation();
+            ItemStack item = new ItemStack(Material.LOG, 1, extraData);
 
-            switch (species) {
+            switch (TreeSpecies.getByData(extraData)) {
             case GENERIC:
-                xp += Config.getInstance().getWoodcuttingXPOak();
+                if (Config.getInstance().getOakDoubleDropsEnabled()) {
+                    Misc.dropItem(location, item);
+                }
                 break;
-
             case REDWOOD:
-                xp += Config.getInstance().getWoodcuttingXPSpruce();
+                if (Config.getInstance().getSpruceDoubleDropsEnabled()) {
+                    Misc.dropItem(location, item);
+                }
                 break;
-
             case BIRCH:
-                xp += Config.getInstance().getWoodcuttingXPBirch();
+                if (Config.getInstance().getBirchDoubleDropsEnabled()) {
+                    Misc.dropItem(location, item);
+                }
                 break;
-
             case JUNGLE:
-                xp += Config.getInstance().getWoodcuttingXPJungle();
+                if (Config.getInstance().getJungleDoubleDropsEnabled()) {
+                    Misc.dropItem(location, item);
+                }
                 break;
-
             default:
                 break;
             }
         }
-
-        Woodcutting.woodCuttingProcCheck(player, block);
-        Skills.xpProcessing(player,  Users.getProfile(player), SkillType.WOODCUTTING, xp);
-    }
-
-    /**
-     * Handle the Leaf Blower ability.
-     *
-     * @param player Player using the ability
-     * @param block Block being broken
-     */
-    public static void leafBlower(Player player, Block block) {
-        mcMMO.p.getServer().getPluginManager().callEvent(new FakePlayerAnimationEvent(player));
-
-        if (mcMMO.spoutEnabled) {
-            SpoutSounds.playSoundForPlayer(SoundEffect.POP, player, block.getLocation());
-        }
-    }
-
-    /**
-     * Calculate the durability loss from Tree Feller
-     *
-     * @param List<Block> Blocks to be felled
-     * @return Durability loss
-     */
-    private static short calulateDurabilityLossFromTreeFeller(List<Block> toBeFelled) {
-        short durabilityLoss = 0;
-        boolean blockModsEnabled = Config.getInstance().getBlockModsEnabled();
-
-        for (Block block : toBeFelled) {
-            if (block.getType() == Material.LOG || (blockModsEnabled && ModChecks.isCustomLogBlock(block))) {
-                durabilityLoss += Misc.toolDurabilityLoss;
-            }
-        }
-
-        return durabilityLoss;
     }
 }

+ 7 - 11
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingCommand.java

@@ -1,13 +1,11 @@
 package com.gmail.nossr50.skills.woodcutting;
 
-import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.skills.SkillCommand;
 import com.gmail.nossr50.skills.SkillType;
 import com.gmail.nossr50.util.Permissions;
 
 public class WoodcuttingCommand extends SkillCommand {
-    AdvancedConfig advancedConfig = AdvancedConfig.getInstance();
     private String treeFellerLength;
     private String treeFellerLengthEndurance;
     private String doubleDropChance;
@@ -16,7 +14,6 @@ public class WoodcuttingCommand extends SkillCommand {
     private boolean canTreeFell;
     private boolean canLeafBlow;
     private boolean canDoubleDrop;
-    private boolean doubleDropsDisabled;
 
     public WoodcuttingCommand() {
         super(SkillType.WOODCUTTING);
@@ -30,7 +27,7 @@ public class WoodcuttingCommand extends SkillCommand {
         treeFellerLengthEndurance = treeFellerStrings[1];
 
         //DOUBLE DROPS
-        String[] doubleDropStrings = calculateAbilityDisplayValues(Woodcutting.doubleDropsMaxLevel, Woodcutting.doubleDropsMaxChance);
+        String[] doubleDropStrings = calculateAbilityDisplayValues(Woodcutting.DOUBLE_DROP_MAX_LEVEL, Woodcutting.DOUBLE_DROP_CHANCE);
         doubleDropChance = doubleDropStrings[0];
         doubleDropChanceLucky = doubleDropStrings[1];
     }
@@ -40,12 +37,11 @@ public class WoodcuttingCommand extends SkillCommand {
         canTreeFell = Permissions.treeFeller(player);
         canDoubleDrop = Permissions.woodcuttingDoubleDrops(player);
         canLeafBlow = Permissions.leafBlower(player);
-        doubleDropsDisabled = Woodcutting.doubleDropsDisabled;
     }
 
     @Override
     protected boolean effectsHeaderPermissions() {
-        return (canDoubleDrop && !doubleDropsDisabled) || canLeafBlow || canTreeFell;
+        return (canDoubleDrop && !Woodcutting.DOUBLE_DROP_DISABLED) || canLeafBlow || canTreeFell;
     }
 
     @Override
@@ -60,28 +56,28 @@ public class WoodcuttingCommand extends SkillCommand {
             player.sendMessage(LocaleLoader.getString("Effects.Template", new Object[] { LocaleLoader.getString("Woodcutting.Effect.2"), LocaleLoader.getString("Woodcutting.Effect.3") }));
         }
 
-        if (canDoubleDrop && !doubleDropsDisabled) {
+        if (canDoubleDrop && !Woodcutting.DOUBLE_DROP_DISABLED) {
             player.sendMessage(LocaleLoader.getString("Effects.Template", new Object[] { LocaleLoader.getString("Woodcutting.Effect.4"), LocaleLoader.getString("Woodcutting.Effect.5") }));
         }
     }
 
     @Override
     protected boolean statsHeaderPermissions() {
-        return (canDoubleDrop && !doubleDropsDisabled) || canLeafBlow || canTreeFell;
+        return (canDoubleDrop && !Woodcutting.DOUBLE_DROP_DISABLED) || canLeafBlow || canTreeFell;
     }
 
     @Override
     protected void statsDisplay() {
         if (canLeafBlow) {
-            if (skillValue < Woodcutting.leafBlowerUnlockLevel) {
-                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", new Object[] { LocaleLoader.getString("Woodcutting.Ability.Locked.0", new Object[] { Woodcutting.leafBlowerUnlockLevel }) }));
+            if (skillValue < Woodcutting.LEAF_BLOWER_UNLOCK_LEVEL) {
+                player.sendMessage(LocaleLoader.getString("Ability.Generic.Template.Lock", new Object[] { LocaleLoader.getString("Woodcutting.Ability.Locked.0", new Object[] { Woodcutting.LEAF_BLOWER_UNLOCK_LEVEL }) }));
             }
             else {
                 player.sendMessage(LocaleLoader.getString("Ability.Generic.Template", new Object[] { LocaleLoader.getString("Woodcutting.Ability.0"), LocaleLoader.getString("Woodcutting.Ability.1") }));
             }
         }
 
-        if (canDoubleDrop && !doubleDropsDisabled) {
+        if (canDoubleDrop && !Woodcutting.DOUBLE_DROP_DISABLED) {
             if (isLucky) {
                 player.sendMessage(LocaleLoader.getString("Woodcutting.Ability.Chance.DDrop", new Object[] { doubleDropChance }) + LocaleLoader.getString("Perks.lucky.bonus", new Object[] { doubleDropChanceLucky }));
             }