diff --git a/Changelog.txt b/Changelog.txt index 633dcd1b5..1dbd3dba2 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -203,6 +203,21 @@ Version 2.2.0 Added API method to check if a skill was being level capped Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill +Version 2.1.115 + Cocoa plants now require GT of at least 2 to start at the second stage of growth + Green Terra now boosts growth on Green Thumb by 1 stage (doesn't go above the maximum value though) + Green Thumb now requires a hoe to activate + You can sneak to break plants with a hoe in your hand (or just put the hoe away) + Hoes no longer give free replants + There is now a feature in place to prevent breaking a newly automatically replanted (via green thumb) crop from being breakable for a few seconds after it appears + Using a hoe on non-fully grown crops will replant them as a convenience feature for those who can't bother to wait for all of their plants to grow (put away the hoe to break non-fully grown crops) + Fixed a bug where Salvage always gave the best results + Fixed an issue with arrows causing exceptions with players not yet having data loaded + Spectral arrows are now tracked by mcMMO + Use minimum level of salvageable properly + Fix Axes Critical Strikes default permissions ( new fixed permission: mcmmo.ability.axes.criticalstrikes ) + Fix potential null pointer exception for salvage + Version 2.1.114 Fix some more locale usages, should aim to further prevent issues with oddball locales Fixed a bug where newer versions of MySQL did not like our rank command diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java b/mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java index b026aa887..bdc81e44c 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java @@ -30,6 +30,7 @@ public class ConfigSound { SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.TIRED, new SoundSetting(1.0, 1.7)); SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.BLEED, new SoundSetting(2.0, 2.0)); SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.GLASS, new SoundSetting(1.0, 1.0)); + SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.ITEM_CONSUMED, new SoundSetting(1.0, 2.0)); } @Setting(value = "Sound-Settings", comment = "Adjust sound settings for various mcMMO sounds here." + diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/core/MetadataConstants.java b/mcmmo-core/src/main/java/com/gmail/nossr50/core/MetadataConstants.java index bc138bc5d..d227577dc 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/core/MetadataConstants.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/core/MetadataConstants.java @@ -8,6 +8,7 @@ import org.bukkit.metadata.FixedMetadataValue; public class MetadataConstants { /* Metadata Values */ + public static final String REPLANT_META_KEY = "mcMMO: Recently Replanted"; public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; public static final String DODGE_TRACKER = "mcMMO: Dodge Tracker"; public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage"; diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java index 60907b342..9aac9b224 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/OldName.java @@ -11,4 +11,5 @@ public class OldName extends FixedMetadataValue { public OldName(String oldName, mcMMO plugin) { super(plugin, oldName); } + } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/RecentlyReplantedCropMeta.java b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/RecentlyReplantedCropMeta.java new file mode 100644 index 000000000..20d8e00df --- /dev/null +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/meta/RecentlyReplantedCropMeta.java @@ -0,0 +1,17 @@ +package com.gmail.nossr50.datatypes.meta; + +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.Plugin; + +public class RecentlyReplantedCropMeta extends FixedMetadataValue { + + /** + * Initializes a FixedMetadataValue with an Object + * + * @param owningPlugin the {@link Plugin} that created this metadata value + */ + public RecentlyReplantedCropMeta(Plugin owningPlugin, Boolean recentlyPlanted) { + super(owningPlugin, recentlyPlanted); + } + +} diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 6feb6091b..96c93c9d9 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -39,6 +39,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/HerbalismBehaviour.java b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/HerbalismBehaviour.java index 4aeadb38e..5dc35ffe6 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/HerbalismBehaviour.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/HerbalismBehaviour.java @@ -23,7 +23,8 @@ public class HerbalismBehaviour { /** * Convert blocks affected by the Green Thumb & Green Terra abilities. * - * @param blockState The {@link BlockState} to check ability activation for + * @param blockState + * The {@link BlockState} to check ability activation for * @return true if the ability was successful, false otherwise */ public boolean convertGreenTerraBlocks(BlockState blockState) { @@ -36,16 +37,16 @@ public class HerbalismBehaviour { blockState.setType(Material.MOSSY_STONE_BRICKS); return true; - case DIRT: - case GRASS_PATH: + case DIRT : + case GRASS_PATH : blockState.setType(Material.GRASS_BLOCK); return true; - case COBBLESTONE: + case COBBLESTONE : blockState.setType(Material.MOSSY_COBBLESTONE); return true; - default: + default : return false; } } @@ -53,29 +54,21 @@ public class HerbalismBehaviour { /** * Convert blocks affected by the Green Thumb & Green Terra abilities. * - * @param blockState The {@link BlockState} to check ability activation for + * @param blockState + * The {@link BlockState} to check ability activation for * @return true if the ability was successful, false otherwise */ public boolean convertShroomThumb(BlockState blockState) { switch (blockState.getType()) { - case DIRT: + case DIRT : case GRASS_BLOCK: - case GRASS_PATH: + case GRASS_PATH : blockState.setType(Material.MYCELIUM); return true; - default: + default : return false; } } - /** - * Check if the block has a recently grown crop from Green Thumb - * - * @param blockState The {@link BlockState} to check green thumb regrown for - * @return true if the block is recently regrown, false otherwise - */ - public boolean isRecentlyRegrown(BlockState blockState) { - return blockState.hasMetadata(MetadataConstants.GREEN_THUMB_METAKEY) && !pluginRef.getSkillTools().cooldownExpired(blockState.getMetadata(MetadataConstants.GREEN_THUMB_METAKEY).get(0).asInt(), 1); - } } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/HolidayManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/HolidayManager.java index 1da8bccd3..7610ef00d 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/HolidayManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/HolidayManager.java @@ -370,7 +370,7 @@ // int levelTotal = Misc.getRandom().nextInt(1 + pluginRef.getUserManager().getPlayer(player).getSkillLevel(PrimarySkillType.MINING)) + 1; // pluginRef.getSoundManager().sendSound(player, player.getLocation(), SoundType.LEVEL_UP); // mcMMO.getNotificationManager().sendPlayerInformation(player, NotificationType.HOLIDAY, "Holiday.AprilFools.Levelup", StringUtils.getCapitalized(fakeSkillType.toString()), String.valueOf(levelTotal)); -//// ParticleEffectUtils.fireworkParticleShower(player, ALL_COLORS.get(Misc.getRandom().nextInt(ALL_COLORS.size()))); +//// pluginRef.getParticleEffectUtils().fireworkParticleShower(player, ALL_COLORS.get(Misc.getRandom().nextInt(ALL_COLORS.size()))); // } // // public void registerAprilCommand() { diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/SalvageManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/SalvageManager.java new file mode 100644 index 000000000..1c2fca938 --- /dev/null +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/dumpster/SalvageManager.java @@ -0,0 +1,330 @@ +//package com.gmail.nossr50.skills.salvage; +// +//import com.gmail.nossr50.config.AdvancedConfig; +//import com.gmail.nossr50.config.Config; +//import com.gmail.nossr50.config.experience.ExperienceConfig; +//import com.gmail.nossr50.datatypes.interactions.NotificationType; +//import com.gmail.nossr50.datatypes.player.McMMOPlayer; +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.datatypes.skills.SubSkillType; +//import com.gmail.nossr50.locale.LocaleLoader; +//import com.gmail.nossr50.mcMMO; +//import com.gmail.nossr50.skills.SkillManager; +//import com.gmail.nossr50.skills.salvage.salvageables.Salvageable; +//import com.gmail.nossr50.util.EventUtils; +//import com.gmail.nossr50.util.Misc; +//import com.gmail.nossr50.util.Permissions; +//import com.gmail.nossr50.util.StringUtils; +//import com.gmail.nossr50.util.player.NotificationManager; +//import com.gmail.nossr50.util.random.RandomChanceSkillStatic; +//import com.gmail.nossr50.util.random.RandomChanceUtil; +//import com.gmail.nossr50.util.skills.RankUtils; +//import com.gmail.nossr50.util.skills.SkillUtils; +//import com.gmail.nossr50.util.sounds.SoundManager; +//import com.gmail.nossr50.util.sounds.SoundType; +//import org.bukkit.Location; +//import org.bukkit.Material; +//import org.bukkit.enchantments.Enchantment; +//import org.bukkit.entity.Player; +//import org.bukkit.inventory.ItemStack; +//import org.bukkit.inventory.meta.EnchantmentStorageMeta; +// +//import java.util.Map; +//import java.util.Map.Entry; +// +//public class SalvageManager extends SkillManager { +// private boolean placedAnvil; +// private int lastClick; +// +// public SalvageManager(McMMOPlayer mcMMOPlayer) { +// super(mcMMOPlayer, PrimarySkillType.SALVAGE); +// } +// +// /** +// * Handles notifications for placing an anvil. +// */ +// public void placedAnvilCheck() { +// Player player = getPlayer(); +// +// if (getPlacedAnvil()) { +// return; +// } +// +// if (Config.getInstance().getSalvageAnvilMessagesEnabled()) { +// NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Listener.Anvil"); +// } +// +// if (Config.getInstance().getSalvageAnvilPlaceSoundsEnabled()) { +// SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); +// } +// +// togglePlacedAnvil(); +// } +// +// public void handleSalvage(Location location, ItemStack item) { +// Player player = getPlayer(); +// +// Salvageable salvageable = mcMMO.getSalvageableManager().getSalvageable(item.getType()); +// +// if (item.getItemMeta() != null && item.getItemMeta().isUnbreakable()) { +// NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Anvil.Unbreakable"); +// return; +// } +// +// // Permissions checks on material and item types +// if (!Permissions.salvageItemType(player, salvageable.getSalvageItemType())) { +// NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); +// return; +// } +// +// if (!Permissions.salvageMaterialType(player, salvageable.getSalvageMaterialType())) { +// NotificationManager.sendPlayerInformation(player, NotificationType.NO_PERMISSION, "mcMMO.NoPermission"); +// return; +// } +// +// /*int skillLevel = getSkillLevel();*/ +// int minimumSalvageableLevel = salvageable.getMinimumLevel(); +// +// // Level check +// if (getSkillLevel() < minimumSalvageableLevel) { +// NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Salvage.Skills.Adept.Level", String.valueOf(RankUtils.getUnlockLevel(SubSkillType.SALVAGE_ARCANE_SALVAGE)), StringUtils.getPrettyItemString(item.getType())); +// return; +// } +// +// int potentialSalvageYield = Salvage.calculateSalvageableAmount(item.getDurability(), salvageable.getMaximumDurability(), salvageable.getMaximumQuantity()); +// +// if (potentialSalvageYield <= 0) { +// NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Salvage.Skills.TooDamaged"); +// return; +// } +// +// potentialSalvageYield = Math.min(potentialSalvageYield, getSalvageLimit()); // Always get at least something back, if you're capable of salvaging it. +// +// player.getInventory().setItemInMainHand(new ItemStack(Material.AIR)); +// location.add(0.5, 1, 0.5); +// +// Map enchants = item.getEnchantments(); +// +// ItemStack enchantBook = null; +// if (!enchants.isEmpty()) { +// enchantBook = arcaneSalvageCheck(enchants); +// } +// +// //Lottery on Salvageable Amount +// +// int lotteryResults = 1; +// int chanceOfSuccess = 99; +// +// for(int x = 0; x < potentialSalvageYield-1; x++) { +// +// if(RandomChanceUtil.rollDice(chanceOfSuccess, 100)) { +// chanceOfSuccess-=3; +// chanceOfSuccess = Math.max(chanceOfSuccess, 90); +// +// lotteryResults+=1; +// } +// } +// +// if(lotteryResults == potentialSalvageYield && potentialSalvageYield != 1 && RankUtils.isPlayerMaxRankInSubSkill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE)) { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Perfect", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); +// } else if(salvageable.getMaximumQuantity() == 1 || getSalvageLimit() >= salvageable.getMaximumQuantity()) { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Normal", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); +// } else { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.Lottery.Untrained", String.valueOf(lotteryResults), StringUtils.getPrettyItemString(item.getType())); +// } +// +// ItemStack salvageResults = new ItemStack(salvageable.getSalvageMaterial(), lotteryResults); +// +// //Call event +// if (EventUtils.callSalvageCheckEvent(player, item, salvageResults, enchantBook).isCancelled()) { +// return; +// } +// +// Location anvilLoc = location.clone(); +// Location playerLoc = player.getLocation().clone(); +// double distance = anvilLoc.distance(playerLoc); +// +// double speedLimit = .6; +// double minSpeed = .3; +// +// //Clamp the speed and vary it by distance +// double vectorSpeed = Math.min(speedLimit, Math.max(minSpeed, distance * .2)); +// +// //Add a very small amount of height +// anvilLoc.add(0, .1, 0); +// +// if (enchantBook != null) { +// Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), enchantBook, vectorSpeed); +// } +// +// Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), salvageResults, vectorSpeed); +// +// // BWONG BWONG BWONG - CLUNK! +// if (Config.getInstance().getSalvageAnvilUseSoundsEnabled()) { +// SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); +// } +// +// NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Skills.Success"); +// } +// +// /*public double getMaxSalvagePercentage() { +// return Math.min((((Salvage.salvageMaxPercentage / Salvage.salvageMaxPercentageLevel) * getSkillLevel()) / 100.0D), Salvage.salvageMaxPercentage / 100.0D); +// }*/ +// +// public int getSalvageLimit() { +// return (RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_SCRAP_COLLECTOR)); +// } +// +// /** +// * Gets the Arcane Salvage rank +// * +// * @return the current Arcane Salvage rank +// */ +// public int getArcaneSalvageRank() { +// return RankUtils.getRank(getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE); +// } +// +// /*public double getExtractFullEnchantChance() { +// int skillLevel = getSkillLevel(); +// +// for (Tier tier : Tier.values()) { +// if (skillLevel >= tier.getLevel()) { +// return tier.getExtractFullEnchantChance(); +// } +// } +// +// return 0; +// } +// +// public double getExtractPartialEnchantChance() { +// int skillLevel = getSkillLevel(); +// +// for (Tier tier : Tier.values()) { +// if (skillLevel >= tier.getLevel()) { +// return tier.getExtractPartialEnchantChance(); +// } +// } +// +// return 0; +// }*/ +// +// public double getExtractFullEnchantChance() { +// if(Permissions.hasSalvageEnchantBypassPerk(getPlayer())) +// return 100.0D; +// +// return AdvancedConfig.getInstance().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); +// } +// +// public double getExtractPartialEnchantChance() { +// return AdvancedConfig.getInstance().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); +// } +// +// private ItemStack arcaneSalvageCheck(Map enchants) { +// Player player = getPlayer(); +// +// if (!RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_ARCANE_SALVAGE) || !Permissions.arcaneSalvage(player)) { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); +// return null; +// } +// +// ItemStack book = new ItemStack(Material.ENCHANTED_BOOK); +// EnchantmentStorageMeta enchantMeta = (EnchantmentStorageMeta) book.getItemMeta(); +// +// boolean downgraded = false; +// int arcaneFailureCount = 0; +// +// for (Entry enchant : enchants.entrySet()) { +// +// int enchantLevel = enchant.getValue(); +// +// if(!ExperienceConfig.getInstance().allowUnsafeEnchantments()) { +// if(enchantLevel > enchant.getKey().getMaxLevel()) { +// enchantLevel = enchant.getKey().getMaxLevel(); +// } +// } +// +// if (!Salvage.arcaneSalvageEnchantLoss +// || Permissions.hasSalvageEnchantBypassPerk(player) +// || RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractFullEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { +// enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel, true); +// } +// else if (enchantLevel > 1 +// && Salvage.arcaneSalvageDowngrades +// && RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getExtractPartialEnchantChance(), getPlayer(), SubSkillType.SALVAGE_ARCANE_SALVAGE))) { +// enchantMeta.addStoredEnchant(enchant.getKey(), enchantLevel - 1, true); +// downgraded = true; +// } else { +// arcaneFailureCount++; +// } +// } +// +// if(failedAllEnchants(arcaneFailureCount, enchants.entrySet().size())) +// { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcaneFailed"); +// return null; +// } else if(downgraded) +// { +// NotificationManager.sendPlayerInformationChatOnly(player, "Salvage.Skills.ArcanePartial"); +// } +// +// book.setItemMeta(enchantMeta); +// return book; +// } +// +// private boolean failedAllEnchants(int arcaneFailureCount, int size) { +// return arcaneFailureCount == size; +// } +// +// /** +// * Check if the player has tried to use an Anvil before. +// * @param actualize +// * +// * @return true if the player has confirmed using an Anvil +// */ +// public boolean checkConfirmation(boolean actualize) { +// Player player = getPlayer(); +// long lastUse = getLastAnvilUse(); +// +// if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getSalvageConfirmRequired()) { +// return true; +// } +// +// if (!actualize) { +// return false; +// } +// +// actualizeLastAnvilUse(); +// +// NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Skills.ConfirmOrCancel", LocaleLoader.getString("Salvage.Pretty.Name")); +// +// return false; +// } +// +// /* +// * Salvage Anvil Placement +// */ +// +// public boolean getPlacedAnvil() { +// return placedAnvil; +// } +// +// public void togglePlacedAnvil() { +// placedAnvil = !placedAnvil; +// } +// +// /* +// * Salvage Anvil Usage +// */ +// +// public int getLastAnvilUse() { +// return lastClick; +// } +// +// public void setLastAnvilUse(int value) { +// lastClick = value; +// } +// +// public void actualizeLastAnvilUse() { +// lastClick = (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR); +// } +//} diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 7f8f99139..f136d6da1 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -397,27 +397,24 @@ public class BlockListener implements Listener { return; } + McMMOPlayer mcMMOPlayer = pluginRef.getUserManager().getPlayer(player); BlockState blockState = event.getBlock().getState(); ItemStack heldItem = player.getInventory().getItemInMainHand(); - if (pluginRef.getDynamicSettingsManager().getSkillBehaviourManager().getHerbalismBehaviour().isRecentlyRegrown(blockState)) { - event.setCancelled(true); - return; - } if (pluginRef.getItemTools().isSword(heldItem)) { - HerbalismManager herbalismManager = pluginRef.getUserManager().getPlayer(player).getHerbalismManager(); + HerbalismManager herbalismManager = mcMMOPlayer.getHerbalismManager(); - if (herbalismManager.canUseHylianLuck()) { - if (herbalismManager.processHylianLuck(blockState)) { - blockState.update(true); - event.setCancelled(true); - } else if (blockState.getType() == Material.FLOWER_POT) { - blockState.setType(Material.AIR); - blockState.update(true); - event.setCancelled(true); + if (herbalismManager.canUseHylianLuck()) { + if (herbalismManager.processHylianLuck(blockState)) { + blockState.update(true); + event.setCancelled(true); + } else if (blockState.getType() == Material.FLOWER_POT) { + blockState.setType(Material.AIR); + blockState.update(true); + event.setCancelled(true); + } } - } } /*else if (!heldItem.containsEnchantment(Enchantment.SILK_TOUCH)) { SmeltingManager smeltingManager = pluginRef.getUserManager().getPlayer(player).getSmeltingManager(); diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 05bfd3333..12078c049 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -352,12 +352,15 @@ public class EntityListener implements Listener { } //Deflect checks - UnarmedManager unarmedManager = pluginRef.getUserManager().getPlayer(defendingPlayer).getUnarmedManager(); + final McMMOPlayer mcMMOPlayer = pluginRef.getUserManager().getPlayer(defendingPlayer); + if (mcMMOPlayer != null) { + UnarmedManager unarmedManager = mcMMOPlayer.getUnarmedManager(); - if (unarmedManager.canDeflect()) { - if(unarmedManager.deflectCheck()) { - event.setCancelled(true); - return; + if (unarmedManager.canDeflect()) { + if (unarmedManager.deflectCheck()) { + event.setCancelled(true); + return; + } } } } else { diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/mcMMO.java b/mcmmo-core/src/main/java/com/gmail/nossr50/mcMMO.java index e03febf7b..abf0eb680 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/mcMMO.java @@ -40,10 +40,7 @@ import com.gmail.nossr50.util.player.PlayerLevelTools; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.RandomChanceTools; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; -import com.gmail.nossr50.util.skills.CombatTools; -import com.gmail.nossr50.util.skills.PerkUtils; -import com.gmail.nossr50.util.skills.RankTools; -import com.gmail.nossr50.util.skills.SkillTools; +import com.gmail.nossr50.util.skills.*; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; @@ -93,6 +90,7 @@ public class mcMMO extends JavaPlugin { private WorldGuardManager worldGuardManager; /* Not-Managers but my naming scheme sucks */ + private ParticleEffectUtils particleEffectUtils; private DatabaseManagerFactory databaseManagerFactory; private ChunkManagerFactory chunkManagerFactory; private CommandTools commandTools; @@ -311,6 +309,9 @@ public class mcMMO extends JavaPlugin { //Init PerkUtils perkUtils = new PerkUtils(this); + + //Init particle effect utils + particleEffectUtils = new ParticleEffectUtils(this); } @Override @@ -870,4 +871,8 @@ public class mcMMO extends JavaPlugin { public PlatformManager getPlatformManager() { return platformManager; } + + public ParticleEffectUtils getParticleEffectUtils() { + return particleEffectUtils; + } } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java b/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java index 1fc5b8920..2b061d1ea 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java @@ -172,7 +172,7 @@ public class BleedTimerTask extends BukkitRunnable { //Play Bleed Sound pluginRef.getSoundManager().worldSendSound(target.getWorld(), target.getLocation(), SoundType.BLEED); - ParticleEffectUtils.playBleedEffect(target); + pluginRef.getParticleEffectUtils().playBleedEffect(target); } //Lower Bleed Ticks diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java b/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java new file mode 100644 index 000000000..877c1e337 --- /dev/null +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/runnables/skills/DelayedCropReplant.java @@ -0,0 +1,101 @@ +package com.gmail.nossr50.runnables.skills; + +import com.gmail.nossr50.core.MetadataConstants; +import com.gmail.nossr50.datatypes.meta.RecentlyReplantedCropMeta; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.ParticleEffectUtils; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.Ageable; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.scheduler.BukkitRunnable; + +public class DelayedCropReplant extends BukkitRunnable { + + private final int desiredCropAge; + private final Location cropLocation; + private final Material cropMaterial; + private boolean wasImmaturePlant; + private final BlockBreakEvent blockBreakEvent; + private final mcMMO pluginRef; + + /** + * Replants a crop after a delay setting the age to desiredCropAge + * @param cropState target {@link BlockState} + * @param desiredCropAge desired age of the crop + */ + public DelayedCropReplant(mcMMO pluginRef, BlockBreakEvent blockBreakEvent, BlockState cropState, int desiredCropAge, boolean wasImmaturePlant) { + this.pluginRef = pluginRef; + //The plant was either immature or something cancelled the event, therefor we need to treat it differently + this.blockBreakEvent = blockBreakEvent; + this.wasImmaturePlant = wasImmaturePlant; + this.cropMaterial = cropState.getType(); + this.desiredCropAge = desiredCropAge; + this.cropLocation = cropState.getLocation(); + } + + @Override + public void run() { + Block cropBlock = cropLocation.getBlock(); + BlockState currentState = cropBlock.getState(); + + //Remove the metadata marking the block as recently replanted + new markPlantAsOld(blockBreakEvent.getBlock().getLocation()).runTaskLater(pluginRef, 20*5); + + if(blockBreakEvent.isCancelled()) { + wasImmaturePlant = true; + } + + //Two kinds of air in Minecraft + if(currentState.getType().equals(cropMaterial) || currentState.getType().equals(Material.AIR) || currentState.getType().equals(Material.CAVE_AIR)) { +// if(currentState.getBlock().getRelative(BlockFace.DOWN)) + //The space is not currently occupied by a block so we can fill it + cropBlock.setType(cropMaterial); + + //Get new state (necessary?) + BlockState newState = cropBlock.getState(); +// newState.update(); + + Ageable ageable = (Ageable) newState.getBlockData(); + + //Crop age should always be 0 if the plant was immature + if(wasImmaturePlant) { + ageable.setAge(0); + } else { + //Otherwise make the plant the desired age + ageable.setAge(desiredCropAge); + } + + //Age the crop + newState.setBlockData(ageable); + newState.update(true); + + //Play an effect + pluginRef.getParticleEffectUtils().playGreenThumbEffect(cropLocation); + + } + + } + + private class markPlantAsOld extends BukkitRunnable { + + private final Location cropLoc; + + public markPlantAsOld(Location cropLoc) { + this.cropLoc = cropLoc; + } + + @Override + public void run() { + Block cropBlock = cropLoc.getBlock(); + if(cropBlock.getMetadata(MetadataConstants.REPLANT_META_KEY).size() > 0) + cropBlock.setMetadata(MetadataConstants.REPLANT_META_KEY, new RecentlyReplantedCropMeta(pluginRef, false)); + + pluginRef.getParticleEffectUtils().playFluxEffect(cropLocation); + } + } + +} diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index 182b25c9d..3deb52181 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -87,7 +87,7 @@ public class AcrobaticsManager extends SkillManager { Player player = getPlayer(); if (!isFatal(modifiedDamage) && pluginRef.getRandomChanceTools().isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_DODGE, player)) { - ParticleEffectUtils.playDodgeEffect(player); + pluginRef.getParticleEffectUtils().playDodgeEffect(player); if (mcMMOPlayer.useChatNotifications()) { pluginRef.getNotificationManager().sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Combat.Proc"); diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index bd5fba7b3..b6884d3df 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -143,7 +143,7 @@ public class AxesManager extends SkillManager { Player player = getPlayer(); - ParticleEffectUtils.playGreaterImpactEffect(target); + pluginRef.getParticleEffectUtils().playGreaterImpactEffect(target); target.setVelocity(player.getLocation().getDirection().normalize().multiply(pluginRef.getConfigManager().getConfigAxes().getGreaterImpactKnockBackModifier())); if (mcMMOPlayer.useChatNotifications()) { diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 35f86daff..78dd03786 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.BlockSnapshot; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.interactions.NotificationType; +import com.gmail.nossr50.datatypes.meta.RecentlyReplantedCropMeta; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; @@ -12,11 +13,15 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.datatypes.skills.behaviours.HerbalismBehaviour; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.runnables.skills.DelayedCropReplant; import com.gmail.nossr50.runnables.skills.DelayedHerbalismXPCheckTask; import com.gmail.nossr50.runnables.skills.HerbalismBlockUpdaterTask; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.StringUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.sounds.SoundManager; +import com.gmail.nossr50.util.sounds.SoundType; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -134,6 +139,23 @@ public class HerbalismManager extends SkillManager { return; } + //Check if the plant was recently replanted + if(blockBreakEvent.getBlock().getBlockData() instanceof Ageable) { + Ageable ageableCrop = (Ageable) blockBreakEvent.getBlock().getBlockData(); + + if(blockBreakEvent.getBlock().getMetadata(MetadataConstants.REPLANT_META_KEY).size() >= 1) { + if(blockBreakEvent.getBlock().getMetadata(MetadataConstants.REPLANT_META_KEY).get(0).asBoolean()) { + if(isAgeableMature(ageableCrop)) { + blockBreakEvent.getBlock().removeMetadata(MetadataConstants.REPLANT_META_KEY, pluginRef); + } else { + //Crop is recently replanted to back out of destroying it + blockBreakEvent.setCancelled(true); + return; + } + } + } + } + /* * There are single-block plants and multi-block plants in Minecraft * In order to give out proper rewards, we need to collect all blocks that would be broken from this event @@ -142,6 +164,9 @@ public class HerbalismManager extends SkillManager { //Grab all broken blocks HashSet brokenBlocks = getBrokenHerbalismBlocks(blockBreakEvent); + if(brokenBlocks.size() == 0) + return; + //Handle rewards, xp, ability interactions, etc processHerbalismOnBlocksBroken(blockBreakEvent, brokenBlocks); } @@ -153,10 +178,19 @@ public class HerbalismManager extends SkillManager { */ private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet brokenPlants) { BlockState originalBreak = blockBreakEvent.getBlock().getState(); + boolean greenThumbActivated = false; //TODO: The design of Green Terra needs to change, this is a mess if(pluginRef.getPermissionTools().greenThumbPlant(getPlayer(), originalBreak.getType())) { - processGreenThumbPlants(originalBreak, isGreenTerraActive()); + if(!getPlayer().isSneaking()) { + greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); + } + + } + + //When replanting a immature crop we cancel the block break event and back out + if(greenThumbActivated) { + return; } /* @@ -339,9 +373,11 @@ public class HerbalismManager extends SkillManager { //Calculate XP if(plantData instanceof Ageable) { Ageable plantAgeable = (Ageable) plantData; + if(isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { xpToReward += pluginRef.getDynamicSettingsManager().getExperienceManager().getHerbalismXp(brokenBlockNewState.getType()); } + } else { xpToReward += pluginRef.getDynamicSettingsManager().getExperienceManager().getHerbalismXp(brokenPlantBlock.getType()); } @@ -437,8 +473,7 @@ public class HerbalismManager extends SkillManager { } private HashSet getBrokenChorusBlocks(BlockState originalBreak) { - HashSet traversedBlocks = grabChorusTreeBrokenBlocksRecursive(originalBreak.getBlock(), new HashSet<>()); - return traversedBlocks; + return grabChorusTreeBrokenBlocksRecursive(originalBreak.getBlock(), new HashSet<>()); } private HashSet grabChorusTreeBrokenBlocksRecursive(Block currentBlock, HashSet traversed) { @@ -565,6 +600,7 @@ public class HerbalismManager extends SkillManager { * @param blockState The {@link BlockState} to check ability activation for * @return true if the ability was successful, false otherwise */ + //TODO: Fix hylian luck? Do we give a #*$%? public boolean processHylianLuck(BlockState blockState) { // if (!pluginRef.getRandomChanceTools().isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.HERBALISM_HYLIAN_LUCK, getPlayer())) { // return false; @@ -631,15 +667,38 @@ public class HerbalismManager extends SkillManager { return herbalismBehaviour.convertShroomThumb(blockState); } + /** + * Starts the delayed replant task and turns + * @param desiredCropAge the desired age of the crop + * @param blockBreakEvent the {@link BlockBreakEvent} this crop was involved in + * @param cropState the {@link BlockState} of the crop + */ + private void startReplantTask(int desiredCropAge, BlockBreakEvent blockBreakEvent, BlockState cropState, boolean isImmature) { + //Mark the plant as recently replanted to avoid accidental breakage + new DelayedCropReplant(pluginRef, blockBreakEvent, cropState, desiredCropAge, isImmature).runTaskLater(pluginRef, 20 * 2); + blockBreakEvent.getBlock().setMetadata(MetadataConstants.REPLANT_META_KEY, new RecentlyReplantedCropMeta(pluginRef, true)); + } + /** * Process the Green Thumb ability for plants. * * @param blockState The {@link BlockState} to check ability activation for * @param greenTerra boolean to determine if greenTerra is active or not */ - private void processGreenThumbPlants(BlockState blockState, boolean greenTerra) { - if (!pluginRef.getBlockTools().isFullyGrown(blockState)) - return; + private boolean processGreenThumbPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) { + if(!pluginRef.getItemTools().isHoe(blockBreakEvent.getPlayer().getInventory().getItemInMainHand())) { + return false; + } + + BlockData blockData = blockState.getBlockData(); + + if (!(blockData instanceof Ageable)) { + return false; + } + + Ageable ageable = (Ageable) blockData; + + //If the ageable is NOT mature and the player is NOT using a hoe, abort Player player = getPlayer(); PlayerInventory playerInventory = player.getInventory(); @@ -671,36 +730,49 @@ public class HerbalismManager extends SkillManager { break; default: - return; + return false; } ItemStack seedStack = new ItemStack(seed); if (!greenTerra && !pluginRef.getRandomChanceTools().checkRandomChanceExecutionSuccess(player, SubSkillType.HERBALISM_GREEN_THUMB)) { - return; + return false; } - if (!processGrowingPlants(blockState, greenTerra)) { - return; + + if (!playerInventory.containsAtLeast(seedStack, 1)) { + return false; } - if (!pluginRef.getItemTools().isHoe(getPlayer().getInventory().getItemInMainHand())) { - if (!playerInventory.containsAtLeast(seedStack, 1)) { - return; - } - - playerInventory.removeItem(seedStack); - player.updateInventory(); // Needed until replacement available + if (!processGrowingPlants(blockState, ageable, blockBreakEvent, greenTerra)) { + return false; } - new HerbalismBlockUpdaterTask(blockState).runTaskLater(pluginRef, 0); + playerInventory.removeItem(seedStack); + player.updateInventory(); // Needed until replacement available + //Play sound + pluginRef.getSoundManager().sendSound(player, player.getLocation(), SoundType.ITEM_CONSUMED); + return true; +// new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0); } - private boolean processGrowingPlants(BlockState blockState, boolean greenTerra) { - int greenThumbStage = getGreenThumbStage(); + private boolean processGrowingPlants(BlockState blockState, Ageable ageable, BlockBreakEvent blockBreakEvent, boolean greenTerra) { + //This check is needed + if(isBizarreAgeable(ageable)) { + return false; + } - blockState.setMetadata(MetadataConstants.GREEN_THUMB_METAKEY, new FixedMetadataValue(pluginRef, (int) (System.currentTimeMillis() / pluginRef.getMiscTools().TIME_CONVERSION_FACTOR))); - Ageable crops = (Ageable) blockState.getBlockData(); + int finalAge = 0; + int greenThumbStage = getGreenThumbStage(greenTerra); + + //Immature plants will start over at 0 + if(!isAgeableMature(ageable)) { +// blockBreakEvent.setCancelled(true); + startReplantTask(0, blockBreakEvent, blockState, true); +// blockState.setType(Material.AIR); + blockBreakEvent.setDropItems(false); + return true; + } switch (blockState.getType()) { @@ -708,42 +780,47 @@ public class HerbalismManager extends SkillManager { case CARROTS: case WHEAT: - if (greenTerra) { - crops.setAge(3); - } else { - crops.setAge(greenThumbStage); - } + finalAge = getGreenThumbStage(greenTerra); break; case BEETROOTS: case NETHER_WART: if (greenTerra || greenThumbStage > 2) { - crops.setAge(2); - } else if (greenThumbStage == 2) { - crops.setAge(1); - } else { - crops.setAge(0); + finalAge = 2; + } + else if (greenThumbStage == 2) { + finalAge = 1; + } + else { + finalAge = 0; } break; case COCOA: - if (greenTerra || getGreenThumbStage() > 1) { - crops.setAge(1); - } else { - crops.setAge(0); + if (getGreenThumbStage(greenTerra) >= 2) { + finalAge = 1; + } + else { + finalAge = 0; } break; default: return false; } - blockState.setBlockData(crops); + + //Start the delayed replant + startReplantTask(finalAge, blockBreakEvent, blockState, false); return true; } - private int getGreenThumbStage() { + private int getGreenThumbStage(boolean greenTerraActive) { + if(greenTerraActive) + return Math.min(pluginRef.getRankTools().getHighestRank(SubSkillType.HERBALISM_GREEN_THUMB), + pluginRef.getRankTools().getRank(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB) + 1); + return pluginRef.getRankTools().getRank(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB); } } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 13a32a6d8..e8f6ba16c 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -208,7 +208,7 @@ public class TamingManager extends SkillManager { if(!pluginRef.getRandomChanceTools().checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(pluginRef, pluginRef.getDynamicSettingsManager().getSkillPropertiesManager().getStaticChance(SubSkillType.TAMING_PUMMEL), getPlayer(), SubSkillType.TAMING_PUMMEL))) return; - ParticleEffectUtils.playGreaterImpactEffect(target); + pluginRef.getParticleEffectUtils().playGreaterImpactEffect(target); target.setVelocity(wolf.getLocation().getDirection().normalize().multiply(1.5D)); if (target instanceof Player) { @@ -381,7 +381,7 @@ public class TamingManager extends SkillManager { callOfWildEntity.setCustomName(pluginRef.getLocaleManager().getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(entityType))); //Particle effect - ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); + pluginRef.getParticleEffectUtils().playCallOfTheWildEffect(callOfWildEntity); } private void spawnHorse(Location spawnLocation) { @@ -408,7 +408,7 @@ public class TamingManager extends SkillManager { callOfWildEntity.setCustomName(pluginRef.getLocaleManager().getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.HORSE))); //Particle effect - ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); + pluginRef.getParticleEffectUtils().playCallOfTheWildEffect(callOfWildEntity); } private void setBaseCOTWEntityProperties(LivingEntity callOfWildEntity) { diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 1dfb82fdf..96d1fdb4e 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -39,7 +39,7 @@ public class TrackedTamingEntity extends BukkitRunnable { if (livingEntity.isValid()) { Location location = livingEntity.getLocation(); location.getWorld().playSound(location, Sound.BLOCK_FIRE_EXTINGUISH, 0.8F, 0.8F); - ParticleEffectUtils.playCallOfTheWildEffect(livingEntity); + pluginRef.getParticleEffectUtils().playCallOfTheWildEffect(livingEntity); pluginRef.getCombatTools().dealDamage(livingEntity, livingEntity.getMaxHealth(), EntityDamageEvent.DamageCause.SUICIDE, livingEntity); if(tamingManagerRef != null) diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/util/player/UserManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/util/player/UserManager.java index bdedafd8f..57dcece50 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/util/player/UserManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/util/player/UserManager.java @@ -8,6 +8,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.metadata.FixedMetadataValue; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -51,9 +52,11 @@ public final class UserManager { public void remove(Player player) { McMMOPlayer mcMMOPlayer = getPlayer(player); player.removeMetadata(MetadataConstants.PLAYER_DATA_METAKEY, pluginRef); - mcMMOPlayer.cleanup(); - if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer)) { + if(mcMMOPlayer != null) + mcMMOPlayer.cleanup(); + + if(playerDataSet != null) { playerDataSet.remove(mcMMOPlayer); //Clear sync save tracking } } @@ -114,10 +117,12 @@ public final class UserManager { * @param playerName The name of the player whose McMMOPlayer to retrieve * @return the player's McMMOPlayer object */ + @Nullable public McMMOPlayer getPlayer(String playerName) { return retrieveMcMMOPlayer(playerName, false); } + @Nullable public McMMOPlayer getOfflinePlayer(OfflinePlayer player) { if (player instanceof Player) { return getPlayer((Player) player); @@ -136,6 +141,7 @@ public final class UserManager { * @param player target player * @return McMMOPlayer object for this player, null if Player has not been loaded */ + @Nullable public McMMOPlayer getPlayer(Player player) { //Avoid Array Index out of bounds if (player != null && player.hasMetadata(MetadataConstants.PLAYER_DATA_METAKEY)) @@ -144,6 +150,7 @@ public final class UserManager { return null; } + @Nullable private McMMOPlayer retrieveMcMMOPlayer(String playerName, boolean offlineValid) { Player player = pluginRef.getServer().getPlayerExact(playerName); diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/CombatTools.java b/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/CombatTools.java index c37528518..d9fc2a098 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/CombatTools.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/CombatTools.java @@ -222,7 +222,7 @@ public final class CombatTools { } - private void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Arrow arrow) { + private void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) { double initialDamage = event.getDamage(); McMMOPlayer mcMMOPlayer = pluginRef.getUserManager().getPlayer(player); @@ -376,8 +376,9 @@ public final class CombatTools { processTamingCombat(target, master, wolf, event); } } - } else if (entityType == EntityType.ARROW) { - Arrow arrow = (Arrow) damager; + } + else if (entityType == EntityType.ARROW || entityType == EntityType.SPECTRAL_ARROW) { + Projectile arrow = (Projectile) damager; ProjectileSource projectileSource = arrow.getShooter(); if (projectileSource instanceof Player && pluginRef.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { @@ -407,11 +408,9 @@ public final class CombatTools { if (metadataValue.size() <= 0) return; - if (metadataValue != null) { - OldName oldName = (OldName) metadataValue.get(0); - entity.setCustomName(oldName.asString()); - entity.setCustomNameVisible(false); - } + OldName oldName = (OldName) metadataValue.get(0); + entity.setCustomName(oldName.asString()); + entity.setCustomNameVisible(false); } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java b/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java index 3199f45b2..e0b6d7f3f 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java @@ -1,5 +1,8 @@ package com.gmail.nossr50.util.skills; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.sounds.SoundManager; +import com.gmail.nossr50.util.sounds.SoundType; import org.bukkit.Effect; import org.bukkit.Location; import org.bukkit.Material; @@ -11,10 +14,19 @@ import org.bukkit.entity.Player; public final class ParticleEffectUtils { - private ParticleEffectUtils() { + private final mcMMO pluginRef; + + public ParticleEffectUtils(mcMMO pluginRef) { + this.pluginRef = pluginRef; } - public static void playBleedEffect(LivingEntity livingEntity) { + public void playGreenThumbEffect(Location location) { + World world = location.getWorld(); + playSmokeEffect(location); + pluginRef.getSoundManager().worldSendSoundMaxPitch(world, location, SoundType.POP); + } + + public void playBleedEffect(LivingEntity livingEntity) { /*if (!MainConfig.getInstance().getBleedEffectEnabled()) { return; }*/ @@ -22,15 +34,15 @@ public final class ParticleEffectUtils { livingEntity.getWorld().playEffect(livingEntity.getEyeLocation(), Effect.STEP_SOUND, Material.REDSTONE_WIRE); } - public static void playDodgeEffect(Player player) { + public void playDodgeEffect(Player player) { /*if (!MainConfig.getInstance().getDodgeEffectEnabled()) { return; }*/ - playSmokeEffect(player); + playSmokeEffect(player.getLocation()); } - public static void playFluxEffect(Location location) { + public void playFluxEffect(Location location) { /*if (!MainConfig.getInstance().getFluxEffectEnabled()) { return; }*/ @@ -38,9 +50,8 @@ public final class ParticleEffectUtils { location.getWorld().playEffect(location, Effect.MOBSPAWNER_FLAMES, 1); } - public static void playSmokeEffect(LivingEntity livingEntity) { - Location location = livingEntity.getEyeLocation(); - World world = livingEntity.getWorld(); + public void playSmokeEffect(Location location) { + World world = location.getWorld(); // Have to do it this way, because not all block directions are valid for smoke world.playEffect(location, Effect.SMOKE, BlockFace.SOUTH_EAST); @@ -54,7 +65,7 @@ public final class ParticleEffectUtils { world.playEffect(location, Effect.SMOKE, BlockFace.NORTH_WEST); } - public static void playGreaterImpactEffect(LivingEntity livingEntity) { + public void playGreaterImpactEffect(LivingEntity livingEntity) { /*if (!MainConfig.getInstance().getGreaterImpactEffectEnabled()) { return; }*/ @@ -64,7 +75,7 @@ public final class ParticleEffectUtils { livingEntity.getWorld().createExplosion(location.getX(), location.getY(), location.getZ(), 0F, false, false); } - public static void playCallOfTheWildEffect(LivingEntity livingEntity) { + public void playCallOfTheWildEffect(LivingEntity livingEntity) { /*if (!MainConfig.getInstance().getCallOfTheWildEffectEnabled()) { return; }*/ @@ -87,7 +98,7 @@ public final class ParticleEffectUtils { firework.setFireworkMeta(fireworkMeta); }*/ - private static boolean hasHeadRoom(Player player) { + private boolean hasHeadRoom(Player player) { boolean hasHeadRoom = true; Block headBlock = player.getEyeLocation().getBlock(); diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java b/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java index 580b8f7af..0ab956ed3 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java @@ -43,6 +43,11 @@ public class SoundManager { world.playSound(location, getSound(soundType), getVolume(soundType), getPitch(soundType)); } + public void worldSendSoundMaxPitch(World world, Location location, SoundType soundType) { + if(pluginRef.getConfigManager().getConfigSound().isSoundEnabled(soundType)) + world.playSound(location, getSound(soundType), getVolume(soundType), 2.0F); + } + /** * All volume is multiplied by the master volume to get its final value * @@ -95,6 +100,8 @@ public class SoundManager { return Sound.ENTITY_ENDER_EYE_DEATH; case GLASS: return Sound.BLOCK_GLASS_BREAK; + case ITEM_CONSUMED: + return Sound.ITEM_BOTTLE_EMPTY; default: return null; } diff --git a/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java b/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java index f1eacd550..517d45cd1 100644 --- a/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java +++ b/mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java @@ -15,6 +15,7 @@ public enum SoundType { ABILITY_ACTIVATED_BERSERK, BLEED, GLASS, + ITEM_CONSUMED, TIRED; public boolean usesCustomPitch() { diff --git a/mcmmo-core/src/main/resources/plugin.yml b/mcmmo-core/src/main/resources/plugin.yml index 5193447cd..38fca6f87 100644 --- a/mcmmo-core/src/main/resources/plugin.yml +++ b/mcmmo-core/src/main/resources/plugin.yml @@ -261,7 +261,7 @@ permissions: description: Allows access to all Axes abilities children: mcmmo.ability.axes.axemastery: true - mcmmo.ability.axes.criticalhit: true + mcmmo.ability.axes.criticalstrikes: true mcmmo.ability.axes.greaterimpact: true mcmmo.ability.axes.armorimpact: true mcmmo.ability.axes.skullsplitter: true @@ -270,8 +270,8 @@ permissions: description: Adds damage to axes mcmmo.ability.axes.axemastery: description: Allows bonus damage from Axes - mcmmo.ability.axes.criticalhit: - description: Allows access to the Critical Hit ability + mcmmo.ability.axes.criticalstrikes: + description: Allows access to the Critical Strikes ability mcmmo.ability.axes.greaterimpact: description: Allows access to the Greater Impact ability mcmmo.ability.axes.armorimpact: diff --git a/mcmmo-core/src/main/resources/sounds.yml b/mcmmo-core/src/main/resources/sounds.yml index 837559568..f705b7d24 100644 --- a/mcmmo-core/src/main/resources/sounds.yml +++ b/mcmmo-core/src/main/resources/sounds.yml @@ -4,6 +4,10 @@ Sounds: # 1.0 = Max volume # 0.0 = No Volume MasterVolume: 1.0 + ITEM_CONSUMED: + Enable: true + Volume: 1.0 + Pitch: 1.0 GLASS: Enable: true Volume: 1.0