From 1bbb245e32c6ad0ac534cb3ac5ad186cf527ba1a Mon Sep 17 00:00:00 2001 From: bm01 Date: Tue, 22 Jan 2013 21:51:07 +0100 Subject: [PATCH] More work on Woodcutting and Tree Feller --- .../nossr50/listeners/BlockListener.java | 23 +- .../skills/woodcutting/TreeFeller.java | 235 +++++++++ .../skills/woodcutting/Woodcutting.java | 486 +++++------------- .../woodcutting/WoodcuttingCommand.java | 18 +- 4 files changed, 376 insertions(+), 386 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/skills/woodcutting/TreeFeller.java diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 2ee5e7912..6df3fe1ca 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/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); } } } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/TreeFeller.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/TreeFeller.java new file mode 100644 index 000000000..c59a3f328 --- /dev/null +++ b/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 treeFellerBlocks = new ArrayList(); + 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 treeFellerBlocks) { + List futureCenterBlocks = new ArrayList(); + 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 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 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 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); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java index 43ddf70c3..6ef1dc212 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java +++ b/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,374 +14,36 @@ 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 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. - * - * @param toBeFelled List of blocks to be removed - * @param player Player using the ability - */ - private static void removeBlocks(List 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); - } - - if (Permissions.woodcutting(player)) { - Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp); - } - } - - /** - * Process Tree Feller around a block. - * - * @param block Point of origin of the layer - * @param toBeFelled List of blocks to be removed - */ - private static void processTreeFellerAroundBlock(Block block, List toBeFelled) { - // TODO: too much duplicate code here - List futureCenterBlocks = new ArrayList(); - 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); - } - - if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) { - treeFellerReachedThreshold = true; - return; - } - } - - 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; - } - } - } - } - - // Recursive call for each log found - for (Block futurCenterBlock : futureCenterBlocks) { - if (treeFellerReachedThreshold) { - return; - } - - processTreeFellerAroundBlock(futurCenterBlock, toBeFelled); - } - } - - /** - * Process Tree Feller. - * - * @param event Event to process - * @return List of blocks to be removed - */ - private static List processTreeFeller(BlockBreakEvent event) { - List toBeFelled = new ArrayList(); - - processTreeFellerAroundBlock(event.getBlock(), toBeFelled); - - if (treeFellerReachedThreshold) { - treeFellerReachedThreshold = false; - - event.getPlayer().sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFellerThreshold")); - return null; - } - - return toBeFelled; - } - - /** - * 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; - } - - 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; - } - } - } - } - - /** - * 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)) { - return; - } - - int xp = 0; - - if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) { - xp = ModChecks.getCustomBlock(block).getXpGain(); - } - else { - byte type = block.getData(); - - if ((type & 0x4) == 0x4) - type ^= 0x4; - - 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; - - switch (species) { - case GENERIC: - xp += Config.getInstance().getWoodcuttingXPOak(); - break; - - case REDWOOD: - xp += Config.getInstance().getWoodcuttingXPSpruce(); - break; - - case BIRCH: - xp += Config.getInstance().getWoodcuttingXPBirch(); - break; - - case JUNGLE: - xp += Config.getInstance().getWoodcuttingXPJungle(); - break; - - default: - break; - } - } - - Woodcutting.woodCuttingProcCheck(player, block); - Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp); - } - - /** - * Handle the Leaf Blower ability. + * Begin Leaf Blower ability. * * @param player Player using the ability * @param block Block being broken */ - public static void leafBlower(Player player, Block block) { + public static void beginLeafBlower(Player player, Block block) { mcMMO.p.getServer().getPluginManager().callEvent(new FakePlayerAnimationEvent(player)); if (mcMMO.spoutEnabled) { @@ -397,21 +52,124 @@ public class Woodcutting { } /** - * Calculate the durability loss from Tree Feller + * Begin Woodcutting process * - * @param List Blocks to be felled - * @return Durability loss + * @param player Player breaking the block + * @param block Block being broken */ - private static short calulateDurabilityLossFromTreeFeller(List toBeFelled) { - short durabilityLoss = 0; - boolean blockModsEnabled = Config.getInstance().getBlockModsEnabled(); + public static void beginWoodcutting(Player player, Block block) { + int xp = 0; - for (Block block : toBeFelled) { - if (block.getType() == Material.LOG || (blockModsEnabled && ModChecks.isCustomLogBlock(block))) { - durabilityLoss += Misc.toolDurabilityLoss; + if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) { + xp = ModChecks.getCustomBlock(block).getXpGain(); + } + else { + try { + xp = getExperienceFromLog(block); + } + catch (IllegalArgumentException exception) { + return; } } - return durabilityLoss; + checkDoubleDrop(player, block); + Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp); + } + + /** + * Retrieve the experience from a log + * + * @param log Log being broken + * @return Amount of experience + * @throws IllegalArgumentException if 'log' is invalid + */ + protected static int getExperienceFromLog(Block log) { + TreeSpecies logType = TreeSpecies.getByData(log.getData()); + + // 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(); + } + + 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 + * + * @param player Player breaking the block + * @param block Block being broken + */ + 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 > DOUBLE_DROP_CHANCE) { + chance = (int) DOUBLE_DROP_CHANCE; + } + + if (chance <= Misc.getRandom().nextInt(activationChance)) { + return; + } + + if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) { + CustomBlock customBlock = ModChecks.getCustomBlock(block); + 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 { + byte extraData = block.getData(); + Location location = block.getLocation(); + ItemStack item = new ItemStack(Material.LOG, 1, extraData); + + switch (TreeSpecies.getByData(extraData)) { + case GENERIC: + if (Config.getInstance().getOakDoubleDropsEnabled()) { + Misc.dropItem(location, item); + } + break; + case REDWOOD: + if (Config.getInstance().getSpruceDoubleDropsEnabled()) { + Misc.dropItem(location, item); + } + break; + case BIRCH: + if (Config.getInstance().getBirchDoubleDropsEnabled()) { + Misc.dropItem(location, item); + } + break; + case JUNGLE: + if (Config.getInstance().getJungleDoubleDropsEnabled()) { + Misc.dropItem(location, item); + } + break; + default: + break; + } + } } } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingCommand.java index 16475c86f..a4de25951 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingCommand.java +++ b/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 })); }