From a66940b2b82ff197ed890621939d3a86ff920ccd Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 30 Jun 2019 12:19:45 -0700 Subject: [PATCH 01/31] Unarmed no longer uses a serverwide cooldown for all players for bonus damage --- Changelog.txt | 1 + pom.xml | 2 +- .../gmail/nossr50/skills/unarmed/Unarmed.java | 2 -- .../skills/unarmed/UnarmedManager.java | 34 ++++++++++++++++--- .../nossr50/util/skills/CombatUtils.java | 2 +- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index ca8f771cf..34c025f03 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,6 @@ Version 2.1.91 mcMMO is now more compatible with plugins that spawn arrows in unexpected ways, this fixes some NPE in mcMMO when using certain plugins + Fixed a bug where Unarmed was using the same CD timer for every player in the server (thanks slop_me) Version 2.1.90 Salvaged items now travel much slower towards the player diff --git a/pom.xml b/pom.xml index b2d5d1425..c8835b4d1 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.91-SNAPSHOT + 2.1.91 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java index 7f4c25c1c..a39cbccc5 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java @@ -10,8 +10,6 @@ import org.bukkit.inventory.ItemStack; public class Unarmed { public static boolean blockCrackerSmoothBrick = Config.getInstance().getUnarmedBlockCrackerSmoothbrickToCracked(); public static double berserkDamageModifier = 1.5; - public static long lastAttacked = 0; - public static long attackInterval = 750; public static void handleItemPickup(Player player, EntityPickupItemEvent event) { ItemStack[] storageContents = player.getInventory().getStorageContents(); diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 44a7b1047..4df9d7903 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -20,17 +20,29 @@ import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.Material; import org.bukkit.block.BlockState; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; public class UnarmedManager extends SkillManager { + private long lastAttacked; + private long attackInterval; + public UnarmedManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.UNARMED); + initUnarmedPerPlayerVars(); } + /** + * Inits variables used for each player for unarmed + */ + private void initUnarmedPerPlayerVars() { + lastAttacked = 0; + attackInterval = 750; + } + + public boolean canActivateAbility() { return mcMMOPlayer.getToolPreparationMode(ToolType.FISTS) && Permissions.berserk(getPlayer()); } @@ -74,8 +86,6 @@ public class UnarmedManager extends SkillManager { return false; } - BlockData data = blockState.getBlockData(); - switch (blockState.getType()) { case STONE_BRICKS: if (!Unarmed.blockCrackerSmoothBrick) { @@ -150,7 +160,7 @@ public class UnarmedManager extends SkillManager { } public boolean isPunchingCooldownOver() { - return (Unarmed.lastAttacked + Unarmed.attackInterval) <= System.currentTimeMillis(); + return (lastAttacked + attackInterval) <= System.currentTimeMillis(); } public double getIronArmDamage() { @@ -181,4 +191,20 @@ public class UnarmedManager extends SkillManager { return false; } + + public long getLastAttacked() { + return lastAttacked; + } + + public void setLastAttacked(long lastAttacked) { + this.lastAttacked = lastAttacked; + } + + public long getAttackInterval() { + return attackInterval; + } + + public void setAttackInterval(long attackInterval) { + this.attackInterval = attackInterval; + } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 5b5aecb04..cd3ffb75a 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -166,7 +166,7 @@ public final class CombatUtils { applyScaledModifiers(initialDamage, finalDamage, event); startGainXp(mcMMOPlayer, target, PrimarySkillType.UNARMED); - Unarmed.lastAttacked = System.currentTimeMillis(); //Track how often the player is punching + unarmedManager.setLastAttacked(System.currentTimeMillis()); //Track how often the player is punching } private static void processTamingCombat(LivingEntity target, Player master, Wolf wolf, EntityDamageByEntityEvent event) { From 53d6065185b5a840d0f1ae40c7e60796530185aa Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 1 Jul 2019 23:50:30 -0700 Subject: [PATCH 02/31] Numerous COTW tweaks --- Changelog.txt | 43 ++ pom.xml | 2 +- .../java/com/gmail/nossr50/config/Config.java | 87 ++-- .../config/experience/ExperienceConfig.java | 1 + .../nossr50/datatypes/player/McMMOPlayer.java | 15 +- .../subskills/taming/CallOfTheWildType.java | 26 ++ .../skills/subskills/taming/TamingSummon.java | 87 ++++ .../nossr50/listeners/EntityListener.java | 15 + .../nossr50/listeners/PlayerListener.java | 7 +- src/main/java/com/gmail/nossr50/mcMMO.java | 1 + .../nossr50/skills/taming/TamingManager.java | 424 ++++++++++++------ .../skills/taming/TrackedTamingEntity.java | 24 +- .../com/gmail/nossr50/util/Permissions.java | 1 - .../nossr50/util/player/UserManager.java | 3 +- src/main/resources/config.yml | 10 +- src/main/resources/experience.yml | 1 + .../resources/locale/locale_en_US.properties | 9 +- 17 files changed, 553 insertions(+), 203 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java create mode 100644 src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java diff --git a/Changelog.txt b/Changelog.txt index 34c025f03..27f661da5 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,46 @@ +Version 2.1.92 + Call Of The Wild (COTW) no longer cares if entities of the same type are nearby when attempting to summon a new entity + By default players are no longer allowed to breed COTW summoned animals with other animals, you can turn this off (see the notes) + Changed the sound effect for COTW (Fireworks -> Pop) + Fixed a bug where COTW summon limit was global instead of per player + The default summon limit for COTW is now per player instead of global which is how it is intended to be, for wolves this defaults to 2, for other entities it defaults to 1 + There is now a small 150ms window in which you cannot summon an entity via COTW to prevent accidentally summoning extra entities + The setting named Summon_Max_Amount in config.yml has been renamed to Per_Player_Limit + COTW entities now send the player a message when they die, time out, or get removed through other means + If the COTW summon has a lifespan, players are now informed about this lifespan when the entity is first summoned + COTW summons now have their name prefixed with some colored text to to make it easier to identify them. + COTW summons now despawn if their owner logs out + If a player tries to breed animals with a COTW animal and the server settings prevent this, they are informed via a message that it is not allowed + Added new setting to experience.yml 'ExploitFix.COTWBreeding' - Prevents breeding with COTW summoned entities when set to true, defaults to true + Removed the 'mcmmo.ability.taming.callofthewild.renamepets' permission node as it is seen as unnecessary + + Removed locale strings + Taming.Summon.Fail.Ocelot + Taming.Summon.Fail.Wolf + Taming.Summon.Fail.Horse + Added new locale strings + Taming.Summon.COTW.BreedingDisallowed + Taming.Summon.COTW.Success + Taming.Summon.COTW.Limit + Taming.Summon.COTW.TimeExpired + Tweaked locale string + Taming.Summon.Name.Format + + NOTES: + I plan to rework Call of The Wild (COTW) significantly in the upcoming content patch, until then I have made several tweaks to it. + + COTW Summoning Requirement Changes + It is intentional that you are not supposed to be able to COTW summon something that you already have tamed, but mcMMO was not checking this properly. + So previous to this patch, if you tried to summon a wolf and wolves were nearby, it would fail. This is not intentional behaviour and was a bug. + The correct behaviour is that if you try to summon a wolf and you already have wolves, it should fail. + I was fixing this bug when it occurred to me, why do we even care if nearby tamed wolves owned by you exist if you are trying to summon a temporary one? + As a result of this train of thought, I have removed this restriction on COTW and several other tweaks have been made as a result of this line of thinking. + There was also an issue involving how many COTW entities could be out at once, for some reason the limit was applied globally and defaulted to 10, so if 10 players had COTW entities out no one else would be able to summon anything. I have fixed this. + You can set the lifespan to 0 in the config to make it so that COTW entities last until a server restart or the player logs out. + + COTW Breeding Change + It was never intentional for COTW summoned entities to be breedable, by default they will not be. You can change this by setting 'ExploitFix.COTWBreeding' to false in experience.yml + Version 2.1.91 mcMMO is now more compatible with plugins that spawn arrows in unexpected ways, this fixes some NPE in mcMMO when using certain plugins Fixed a bug where Unarmed was using the same CD timer for every player in the server (thanks slop_me) diff --git a/pom.xml b/pom.xml index c8835b4d1..b19452d2c 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.91 + 2.1.92-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index ac272521f..692ae055c 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -198,41 +198,41 @@ public class Config extends AutoUpdateConfigLoader { reason.add("Cannot use the same item for Repair and Salvage anvils!"); } - if (getTamingCOTWMaterial(EntityType.WOLF) == null) { - reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!"); - } - - if (getTamingCOTWMaterial(EntityType.OCELOT) == null) { - reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!"); - } - - if (getTamingCOTWMaterial(EntityType.HORSE) == null) { - reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!"); - } - - if (getTamingCOTWCost(EntityType.WOLF) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!"); - } - - if (getTamingCOTWCost(EntityType.OCELOT) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!"); - } - - if (getTamingCOTWCost(EntityType.HORSE) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!"); - } - - if (getTamingCOTWAmount(EntityType.WOLF) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!"); - } - - if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!"); - } - - if (getTamingCOTWAmount(EntityType.HORSE) <= 0) { - reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!"); - } +// if (getTamingCOTWMaterial(EntityType.WOLF) == null) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!"); +// } +// +// if (getTamingCOTWMaterial(EntityType.OCELOT) == null) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!"); +// } +// +// if (getTamingCOTWMaterial(EntityType.HORSE) == null) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!"); +// } +// +// if (getTamingCOTWCost(EntityType.WOLF) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!"); +// } +// +// if (getTamingCOTWCost(EntityType.OCELOT) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!"); +// } +// +// if (getTamingCOTWCost(EntityType.HORSE) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!"); +// } +// +// if (getTamingCOTWAmount(EntityType.WOLF) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!"); +// } +// +// if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!"); +// } +// +// if (getTamingCOTWAmount(EntityType.HORSE) <= 0) { +// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!"); +// } return noErrorsInConfig(reason); } @@ -529,12 +529,17 @@ public class Config extends AutoUpdateConfigLoader { public int getSwordsGate() { return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10); } /* Taming */ - public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); } - public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); } - public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); } - public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); } - public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); } - public double getTamingCOTWRange() { return config.getDouble("Skills.Taming.Call_Of_The_Wild.Range", 40.0D); } +// public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); } +// public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); } +// public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); } +// public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); } +// public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); } + + public Material getTamingCOTWMaterial(String cotwEntity) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material")); } + public int getTamingCOTWCost(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Amount"); } + public int getTamingCOTWAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Amount"); } + public int getTamingCOTWLength(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Summon_Length"); } + public int getTamingCOTWMaxAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Per_Player_Limit", 1); } /* Woodcutting */ public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) { return config.getBoolean("Bonus_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material)); } diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 052cf43b6..a6f6ef26c 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -147,6 +147,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader { public boolean isEndermanEndermiteFarmingPrevented() { return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true); } public boolean isPistonExploitPrevented() { return config.getBoolean("ExploitFix.Pistons", false); } public boolean allowUnsafeEnchantments() { return config.getBoolean("ExploitFix.UnsafeEnchantments", false); } + public boolean isCOTWBreedingPrevented() { return config.getBoolean("ExploitFix.COTWBreeding", true); } public boolean isFishingExploitingPrevented() { return config.getBoolean("ExploitFix.Fishing", true); } public boolean isAcrobaticsExploitingPrevented() { return config.getBoolean("ExploitFix.Acrobatics", true); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index d6ed18ee8..f4986d5f4 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -1026,8 +1026,8 @@ public class McMMOPlayer { */ public void logout(boolean syncSave) { Player thisPlayer = getPlayer(); - resetAbilityMode(); - BleedTimerTask.bleedOut(thisPlayer); + BleedTimerTask.bleedOut(getPlayer()); + cleanup(); if (syncSave) { getProfile().save(true); @@ -1047,4 +1047,15 @@ public class McMMOPlayer { //Remove user from cache mcMMO.getDatabaseManager().cleanupUser(thisPlayer.getUniqueId()); } + + /** + * Cleanup various things related to this player + * Such as temporary summons.. + * Turning off abilities... + * Etc... + */ + public void cleanup() { + resetAbilityMode(); + getTamingManager().cleanupAllSummons(); + } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java new file mode 100644 index 000000000..9a88fc295 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/CallOfTheWildType.java @@ -0,0 +1,26 @@ +package com.gmail.nossr50.datatypes.skills.subskills.taming; + +import com.gmail.nossr50.util.StringUtils; +import org.bukkit.entity.EntityType; + +public enum CallOfTheWildType { + WOLF, + CAT, + HORSE; + + //TODO: This is a hacky fix to make the COTW code in 2.1 more bearable, this will be removed upon the rework planned for COTW + public String getConfigEntityTypeEntry() { + + switch(this) { + case CAT: + return StringUtils.getPrettyEntityTypeString(EntityType.OCELOT); //Even though cats will be summoned in 1.14, we specify Ocelot here. This will be gone in 2.2 + case WOLF: + return StringUtils.getPrettyEntityTypeString(EntityType.WOLF); + case HORSE: + return StringUtils.getPrettyEntityTypeString(EntityType.HORSE); + } + + return null; + } + +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java new file mode 100644 index 000000000..ebb2a5690 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/taming/TamingSummon.java @@ -0,0 +1,87 @@ +package com.gmail.nossr50.datatypes.skills.subskills.taming; + +import org.bukkit.Material; +import org.bukkit.entity.EntityType; + +/** + * Data Container for properties used in summoning an entity via COTW + */ +public class TamingSummon { + + private Material itemType; + private int itemAmountRequired; + private int entitiesSummoned; + private int summonLifespan; + private int summonCap; + private CallOfTheWildType callOfTheWildType; + private EntityType entityType; + + public TamingSummon(CallOfTheWildType callOfTheWildType, Material itemType, int itemAmountRequired, int entitiesSummoned, int summonLifespan, int summonCap) { + this.callOfTheWildType = callOfTheWildType; + this.itemType = itemType; + this.itemAmountRequired = Math.max(itemAmountRequired, 1); + this.entitiesSummoned = Math.max(entitiesSummoned, 1); + this.summonLifespan = summonLifespan; + this.summonCap = Math.max(summonCap, 1); + + initEntityType(); + } + + private void initEntityType() { + switch(callOfTheWildType) { + case WOLF: + entityType = EntityType.WOLF; + break; + case HORSE: + entityType = EntityType.HORSE; + break; + case CAT: + if(shouldSpawnCatInsteadOfOcelot()) { + //Server is on 1.14 or above + entityType = EntityType.CAT; + } else { + //Server is not on 1.14 or above + entityType = EntityType.OCELOT; + } + } + } + + private boolean shouldSpawnCatInsteadOfOcelot() { + try { + Class clazz = Class.forName("org.bukkit.entity.Panda"); + //Panda exists which means this is at least 1.14, so we should spawn a cat instead of ocelot + return true; + } catch (ClassNotFoundException e) { + /*e.printStackTrace();*/ + return false; + } + } + + public EntityType getEntityType() { + return entityType; + } + + public Material getItemType() { + return itemType; + } + + public int getItemAmountRequired() { + return itemAmountRequired; + } + + public int getEntitiesSummoned() { + return entitiesSummoned; + } + + public int getSummonLifespan() { + return summonLifespan; + } + + public int getSummonCap() { + return summonCap; + } + + public CallOfTheWildType getCallOfTheWildType() { + return callOfTheWildType; + } +} diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 69ca40c52..b69dc4a83 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -21,6 +21,7 @@ import com.gmail.nossr50.skills.unarmed.UnarmedManager; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; @@ -733,6 +734,20 @@ public class EntityListener implements Listener { } } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntityBreed(EntityBreedEvent event) { + if(ExperienceConfig.getInstance().isCOTWBreedingPrevented()) { + if(event.getFather().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON) || event.getMother().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON)) { + event.setCancelled(true); + } + + if(event.getBreeder() instanceof Player) { + Player player = (Player) event.getBreeder(); + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.BreedingDisallowed"); + } + } + } + /** * Handle ExplosionPrime events that involve modifying the event. * diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 34f84ad60..ffdaf4731 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -11,6 +11,7 @@ import com.gmail.nossr50.datatypes.party.Party; 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.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -827,13 +828,13 @@ public class PlayerListener implements Listener { Material type = heldItem.getType(); TamingManager tamingManager = mcMMOPlayer.getTamingManager(); - if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.WOLF)) { + if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { tamingManager.summonWolf(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.OCELOT)) { + else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { tamingManager.summonOcelot(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.HORSE)) { + else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { tamingManager.summonHorse(); } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 00460dce3..79c0e689e 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -108,6 +108,7 @@ public class mcMMO extends JavaPlugin { /* Metadata Values */ public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage"; + public static final String COTW_TEMPORARY_SUMMON = "mcMMO: COTW Entity"; public final static String entityMetadataKey = "mcMMO: Spawned Entity"; public final static String blockMetadataKey = "mcMMO: Piston Tracking"; public final static String furnaceMetadataKey = "mcMMO: Tracked Furnace"; diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 1ebcb5344..9d55c6057 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -8,7 +8,8 @@ import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.events.fake.FakeEntityTameEvent; +import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; +import com.gmail.nossr50.datatypes.skills.subskills.taming.TamingSummon; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.BleedTimerTask; @@ -22,7 +23,10 @@ import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.RankUtils; 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.Sound; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; @@ -32,11 +36,66 @@ import java.util.HashMap; import java.util.List; public class TamingManager extends SkillManager { + //TODO: Temporary static cache, will be changed in 2.2 + private static HashMap summoningItems; + private static HashMap cotwSummonDataProperties; + private long lastSummonTimeStamp; + + private HashMap> playerSummonedEntities; + public TamingManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.TAMING); + init(); } - private static HashMap> summonedEntities = new HashMap>(); + //TODO: Hacky stuff for 2.1, will be cleaned up in 2.2 + private void init() { + //prevents accidentally summoning too many things when holding down left click + lastSummonTimeStamp = 0L; + + //Init per-player tracking of summoned entities + initPerPlayerSummonTracking(); + + //Hacky stuff used as a band-aid + initStaticCaches(); + } + + private void initPerPlayerSummonTracking() { + playerSummonedEntities = new HashMap<>(); + + for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { + playerSummonedEntities.put(callOfTheWildType, new ArrayList()); + } + } + + private void initStaticCaches() { + //TODO: Temporary static cache, will be changed in 2.2 + //This is shared between instances of TamingManager + if(summoningItems == null) { + summoningItems = new HashMap<>(); + + summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); + summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); + summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); + } + + //TODO: Temporary static cache, will be changed in 2.2 + //This is shared between instances of TamingManager + if(cotwSummonDataProperties == null) { + cotwSummonDataProperties = new HashMap<>(); + + for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { + Material itemSummonMaterial = Config.getInstance().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); + int itemAmountRequired = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int entitiesSummonedPerCOTW = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int summonLifespanSeconds = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int perPlayerMaxAmount = Config.getInstance().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); + + TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, perPlayerMaxAmount); + cotwSummonDataProperties.put(callOfTheWildType, tamingSummon); + } + } + } public boolean canUseThickFur() { return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_THICK_FUR) @@ -98,7 +157,6 @@ public class TamingManager extends SkillManager { * @param damage The damage being absorbed by the wolf */ public void fastFoodService(Wolf wolf, double damage) { - //static chance (3rd param) if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) { return; } @@ -150,7 +208,7 @@ public class TamingManager extends SkillManager { return; } - callOfTheWild(EntityType.OCELOT, Config.getInstance().getTamingCOTWCost(EntityType.OCELOT)); + processCallOfTheWild(); } /** @@ -164,7 +222,7 @@ public class TamingManager extends SkillManager { return; } - callOfTheWild(EntityType.WOLF, Config.getInstance().getTamingCOTWCost(EntityType.WOLF)); + processCallOfTheWild(); } /** @@ -178,7 +236,7 @@ public class TamingManager extends SkillManager { return; } - callOfTheWild(EntityType.HORSE, Config.getInstance().getTamingCOTWCost(EntityType.HORSE)); + processCallOfTheWild(); } /** @@ -257,151 +315,243 @@ public class TamingManager extends SkillManager { } } + + private void processCallOfTheWild() { + //Prevent summoning too many things accidentally if a player holds down the button + if(lastSummonTimeStamp + 150 > System.currentTimeMillis()) { + return; + } else { + lastSummonTimeStamp = System.currentTimeMillis(); + } + + Player player = getPlayer(); + ItemStack itemInMainHand = player.getInventory().getItemInMainHand(); + + //Check if the item the player is currently holding is a COTW item + if(isCOTWItem(itemInMainHand)) { + //Get the summoning type + CallOfTheWildType callOfTheWildType = summoningItems.get(itemInMainHand.getType()); + TamingSummon tamingSummon = cotwSummonDataProperties.get(callOfTheWildType); + + + //Check to see if players have the correct amount of the item required to summon + if(itemInMainHand.getAmount() >= tamingSummon.getItemAmountRequired()) { + //Initial Spawn location + Location spawnLocation = Misc.getLocationOffset(player.getLocation(), 1); + + //COTW can summon multiple entities per usage + for (int i = 0; i < tamingSummon.getEntitiesSummoned(); i++) { + + if (getAmountCurrentlySummoned(callOfTheWildType) >= tamingSummon.getSummonCap()) { + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Taming.Summon.COTW.Limit", String.valueOf(tamingSummon.getSummonCap())); + break; + } + + spawnLocation = Misc.getLocationOffset(spawnLocation, 1); + spawnCOTWEntity(callOfTheWildType, spawnLocation, tamingSummon.getEntityType()); + } + + //Remove the items used to summon + int itemAmountAfterPayingCost = itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired(); + itemInMainHand.setAmount(itemAmountAfterPayingCost); + player.updateInventory(); + + //Inform the player about what they have just done + if (tamingSummon.getSummonLifespan() > 0) { + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.COTW.Success", + StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan())); + } else { + NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.Complete"); + } + + //Send Sound + SoundManager.sendSound(player, player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + + } else { + //Player did not have enough of the item in their main hand + int difference = tamingSummon.getItemAmountRequired() - itemInMainHand.getAmount(); + NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.NotEnough", String.valueOf(difference), StringUtils.getPrettyItemString(itemInMainHand.getType())); + } + } + + } + + private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) { + switch(callOfTheWildType) { + case CAT: + //Entity type is needed for cats because in 1.13 and below we spawn ocelots, in 1.14 and above we spawn cats + spawnCat(spawnLocation, entityType); + break; + case HORSE: + spawnHorse(spawnLocation); + break; + case WOLF: + spawnWolf(spawnLocation); + break; + } + } + + private void spawnWolf(Location spawnLocation) { + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.WOLF); + + //This is used to prevent XP gains for damaging this entity + applyMetaDataToCOTWEntity(callOfWildEntity); + + setBaseCOTWEntityProperties(callOfWildEntity); + + addToTracker(callOfWildEntity, CallOfTheWildType.WOLF); + + //Setup wolf stats + callOfWildEntity.setMaxHealth(20.0); + callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); + + callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.WOLF))); + } + + private void spawnCat(Location spawnLocation, EntityType entityType) { + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, entityType); + + //This is used to prevent XP gains for damaging this entity + applyMetaDataToCOTWEntity(callOfWildEntity); + + setBaseCOTWEntityProperties(callOfWildEntity); + + addToTracker(callOfWildEntity, CallOfTheWildType.CAT); + + //Randomize the cat + if(callOfWildEntity instanceof Ocelot) { + int numberOfTypes = Ocelot.Type.values().length; + ((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); + } else if(callOfWildEntity instanceof Cat) { + int numberOfTypes = Cat.Type.values().length; + ((Cat) callOfWildEntity).setCatType(Cat.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); + } + + callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(entityType))); + + //Particle effect + ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); + } + + private void spawnHorse(Location spawnLocation) { + LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.HORSE); + applyMetaDataToCOTWEntity(callOfWildEntity); + + setBaseCOTWEntityProperties(callOfWildEntity); + + addToTracker(callOfWildEntity, CallOfTheWildType.HORSE); + + //Randomize Horse + Horse horse = (Horse) callOfWildEntity; + + callOfWildEntity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15)); + callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); + horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); + horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); + horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); + //TODO: setSpeed, once available + + callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.HORSE))); + + //Particle effect + ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); + } + + private void setBaseCOTWEntityProperties(LivingEntity callOfWildEntity) { + ((Tameable) callOfWildEntity).setOwner(getPlayer()); + callOfWildEntity.setRemoveWhenFarAway(false); + } + + private void applyMetaDataToCOTWEntity(LivingEntity callOfWildEntity) { + //This is used to prevent XP gains for damaging this entity + callOfWildEntity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue); + + //This helps identify the entity as being summoned by COTW + callOfWildEntity.setMetadata(mcMMO.COTW_TEMPORARY_SUMMON, mcMMO.metadataValue); + } + /** - * Handle the Call of the Wild ability. - * - * @param type The type of entity to summon. - * @param summonAmount The amount of material needed to summon the entity + * Whether or not the itemstack is used for COTW + * @param itemStack target ItemStack + * @return true if it is used for any COTW */ - private void callOfTheWild(EntityType type, int summonAmount) { - Player player = getPlayer(); - - ItemStack heldItem = player.getInventory().getItemInMainHand(); - int heldItemAmount = heldItem.getAmount(); - Location location = player.getLocation(); - - if (heldItemAmount < summonAmount) { - int moreAmount = summonAmount - heldItemAmount; - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.NotEnough", String.valueOf(moreAmount), StringUtils.getPrettyItemString(heldItem.getType())); - return; - } - - if (!rangeCheck(type)) { - return; - } - - int amount = Config.getInstance().getTamingCOTWAmount(type); - int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(type); - - for (int i = 0; i < amount; i++) { - if (!summonAmountCheck(type)) { - return; - } - - location = Misc.getLocationOffset(location, 1); - LivingEntity callOfWildEntity = (LivingEntity) player.getWorld().spawnEntity(location, type); - - FakeEntityTameEvent event = new FakeEntityTameEvent(callOfWildEntity, player); - mcMMO.p.getServer().getPluginManager().callEvent(event); - - if (event.isCancelled()) { - continue; - } - - callOfWildEntity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue); - ((Tameable) callOfWildEntity).setOwner(player); - callOfWildEntity.setRemoveWhenFarAway(false); - - addToTracker(callOfWildEntity); - - switch (type) { - case OCELOT: - ((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[1 + Misc.getRandom().nextInt(3)]); - break; - - case WOLF: - callOfWildEntity.setMaxHealth(20.0); - callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); - break; - - case HORSE: - Horse horse = (Horse) callOfWildEntity; - - callOfWildEntity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15)); - callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); - horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); - horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); - horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); - //TODO: setSpeed, once available - break; - - default: - break; - } - - if (Permissions.renamePets(player)) { - callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", player.getName(), StringUtils.getPrettyEntityTypeString(type))); - } - - ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity); - } - - ItemStack leftovers = new ItemStack(heldItem); - leftovers.setAmount(heldItemAmount - summonAmount); - player.getInventory().setItemInMainHand(heldItemAmount == summonAmount ? null : leftovers); - - String lifeSpan = ""; - if (tamingCOTWLength > 0) { - lifeSpan = LocaleLoader.getString("Taming.Summon.Lifespan", tamingCOTWLength); - } - - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.Complete", lifeSpan); - player.playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1F, 0.5F); + public boolean isCOTWItem(ItemStack itemStack) { + return summoningItems.containsKey(itemStack.getType()); } - private boolean rangeCheck(EntityType type) { - double range = Config.getInstance().getTamingCOTWRange(); - Player player = getPlayer(); + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + private int getAmountCurrentlySummoned(CallOfTheWildType callOfTheWildType) { + //The tracker is unreliable so validate its contents first + recalibrateTracker(); - if (range == 0) { - return true; + return playerSummonedEntities.get(callOfTheWildType).size(); + } + + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + private void addToTracker(LivingEntity livingEntity, CallOfTheWildType callOfTheWildType) { + TrackedTamingEntity trackedEntity = new TrackedTamingEntity(livingEntity, callOfTheWildType, this); + + playerSummonedEntities.get(callOfTheWildType).add(trackedEntity); + } + + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + public List getTrackedEntities(CallOfTheWildType callOfTheWildType) { + return playerSummonedEntities.get(callOfTheWildType); + } + + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + public void removeFromTracker(TrackedTamingEntity trackedEntity) { + if(playerSummonedEntities.get(trackedEntity.getCallOfTheWildType()).contains(trackedEntity)) + playerSummonedEntities.get(trackedEntity.getCallOfTheWildType()).remove(trackedEntity); + + NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Taming.Summon.COTW.TimeExpired", StringUtils.getPrettyEntityTypeString(trackedEntity.getLivingEntity().getType())); + } + + /** + * Builds a new tracked list by determining which tracked things are still valid + */ + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + private void recalibrateTracker() { + for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { + ArrayList validEntities = getValidTrackedEntities(callOfTheWildType); + playerSummonedEntities.put(callOfTheWildType, validEntities); //Replace the old list with the new list } + } - for (Entity entity : player.getNearbyEntities(range, range, range)) { - if (entity.getType() == type) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, Taming.getCallOfTheWildFailureMessage(type)); - return false; + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + private ArrayList getValidTrackedEntities(CallOfTheWildType callOfTheWildType) { + ArrayList validTrackedEntities = new ArrayList<>(); + + for(TrackedTamingEntity trackedTamingEntity : getTrackedEntities(callOfTheWildType)) { + LivingEntity livingEntity = trackedTamingEntity.getLivingEntity(); + + //Remove from existence + if(livingEntity != null && livingEntity.isValid()) { + validTrackedEntities.add(trackedTamingEntity); } } - return true; + return validTrackedEntities; } - private boolean summonAmountCheck(EntityType entityType) { - Player player = getPlayer(); + /** + * Remove all tracked entities from existence if they currently exist + * Clear the tracked entity lists afterwards + */ + //TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update + public void cleanupAllSummons() { + for(List trackedTamingEntities : playerSummonedEntities.values()) { + for(TrackedTamingEntity trackedTamingEntity : trackedTamingEntities) { + LivingEntity livingEntity = trackedTamingEntity.getLivingEntity(); - int maxAmountSummons = Config.getInstance().getTamingCOTWMaxAmount(entityType); + //Remove from existence + if(livingEntity != null && livingEntity.isValid()) { + livingEntity.remove(); + } + } - if (maxAmountSummons <= 0) { - return true; + //Clear the list + trackedTamingEntities.clear(); } - - List trackedEntities = getTrackedEntities(entityType); - int summonAmount = trackedEntities == null ? 0 : trackedEntities.size(); - - if (summonAmount >= maxAmountSummons) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Taming.Summon.Fail.TooMany", String.valueOf(maxAmountSummons)); - return false; - } - - return true; - } - - protected static void addToTracker(LivingEntity livingEntity) { - TrackedTamingEntity trackedEntity = new TrackedTamingEntity(livingEntity); - - if (!summonedEntities.containsKey(livingEntity.getType())) { - summonedEntities.put(livingEntity.getType(), new ArrayList()); - } - - summonedEntities.get(livingEntity.getType()).add(trackedEntity); - } - - protected static List getTrackedEntities(EntityType entityType) { - return summonedEntities.get(entityType); - } - - protected static void removeFromTracker(TrackedTamingEntity trackedEntity) { - summonedEntities.get(trackedEntity.getLivingEntity().getType()).remove(trackedEntity); } } diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 51bb6afb7..6028d97c4 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.skills.taming; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.CombatUtils; @@ -15,14 +16,18 @@ import java.util.UUID; public class TrackedTamingEntity extends BukkitRunnable { private LivingEntity livingEntity; + private final CallOfTheWildType callOfTheWildType; private UUID id; private int length; + private final TamingManager tamingManagerRef; - protected TrackedTamingEntity(LivingEntity livingEntity) { + protected TrackedTamingEntity(LivingEntity livingEntity, CallOfTheWildType callOfTheWildType, TamingManager tamingManagerRef) { + this.tamingManagerRef = tamingManagerRef; + this.callOfTheWildType = callOfTheWildType; this.livingEntity = livingEntity; this.id = livingEntity.getUniqueId(); - int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(livingEntity.getType()); + int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); if (tamingCOTWLength > 0) { this.length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR; @@ -36,18 +41,25 @@ public class TrackedTamingEntity extends BukkitRunnable { Location location = livingEntity.getLocation(); location.getWorld().playSound(location, Sound.BLOCK_FIRE_EXTINGUISH, 0.8F, 0.8F); ParticleEffectUtils.playCallOfTheWildEffect(livingEntity); - CombatUtils.dealDamage(livingEntity, livingEntity.getMaxHealth(), DamageCause.SUICIDE, livingEntity); + + if(tamingManagerRef != null) + tamingManagerRef.removeFromTracker(this); + + livingEntity.remove(); } - TamingManager.removeFromTracker(this); this.cancel(); } - protected LivingEntity getLivingEntity() { + public CallOfTheWildType getCallOfTheWildType() { + return callOfTheWildType; + } + + public LivingEntity getLivingEntity() { return livingEntity; } - protected UUID getID() { + public UUID getID() { return id; } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 0e3d6e632..483fa9c43 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -192,7 +192,6 @@ public final class Permissions { /* TAMING */ public static boolean callOfTheWild(Permissible permissible, EntityType type) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild." + type.toString().toLowerCase()); } - public static boolean renamePets(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild.renamepets"); } /* UNARMED */ public static boolean berserk(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.unarmed.berserk"); } diff --git a/src/main/java/com/gmail/nossr50/util/player/UserManager.java b/src/main/java/com/gmail/nossr50/util/player/UserManager.java index ffb898086..b2044766c 100644 --- a/src/main/java/com/gmail/nossr50/util/player/UserManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/UserManager.java @@ -46,8 +46,9 @@ public final class UserManager { McMMOPlayer mcMMOPlayer = getPlayer(player); player.removeMetadata(mcMMO.playerDataKey, mcMMO.p); - if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer)) + if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer)) { playerDataSet.remove(mcMMOPlayer); //Clear sync save tracking + } } /** diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 90140e40a..675d1a811 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -391,23 +391,19 @@ Skills: Item_Amount: 10 Summon_Amount: 1 Summon_Length: 240 - Summon_Max_Amount: 10 + Per_Player_Limit: 2 Ocelot: Item_Material: COD Item_Amount: 10 Summon_Amount: 1 Summon_Length: 240 - Summon_Max_Amount: 10 + Per_Player_Limit: 1 Horse: Item_Material: APPLE Item_Amount: 10 Summon_Amount: 1 Summon_Length: 240 - Summon_Max_Amount: 10 - - # Range to check for nearby pets when using Call Of The Wild, 0 will disable the check - Range: 40.0 - + Per_Player_Limit: 1 Unarmed: Enabled_For_PVP: true Enabled_For_PVE: true diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index faeb5a6c3..94052a786 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -25,6 +25,7 @@ EarlyGameBoost: Enabled: true ExploitFix: + COTWBreeding: true UnsafeEnchantments: false # Prevent many exploits related to fishing Fishing: true diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 1e1d0c5b0..e8ad00393 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -481,12 +481,13 @@ Taming.Listener.Wolf=[[DARK_GRAY]]Your wolf scurries back to you... Taming.Listener=Taming: Taming.SkillName=TAMING Taming.Summon.Complete=[[GREEN]]Summoning complete +Taming.Summon.COTW.Success=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] and it has a duration of [[GOLD]]{1}[[GRAY]] seconds. Taming.Summon.Lifespan= (Lifespan: {0}s) -Taming.Summon.Fail.Ocelot=[[RED]]You have too many ocelots nearby to summon any more. -Taming.Summon.Fail.Wolf=[[RED]]You have too many wolves nearby to summon any more. -Taming.Summon.Fail.Horse=[[RED]]You have too many horses nearby to summon any more. Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0}) -Taming.Summon.Name.Format={0}'s {1} +Taming.Summon.COTW.Limit=[[RED]]You can only summon up to {0} for this type of animal. Try again later. +Taming.Summon.COTW.TimeExpired=[[GREEN]](Call Of The Wild) [[GRAY]]Time is up, your temporary summon [[GOLD]]{0}[[GRAY]] departs. +Taming.Summon.COTW.BreedingDisallowed=[[GREEN]](Call Of The Wild) [[RED]]You cannot breed a summoned animal. +Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0}'s {1} #UNARMED Unarmed.Ability.Bonus.0=Iron Arm Style Unarmed.Ability.Bonus.1=+{0} DMG Upgrade From a19ddb46b6d80688d1b53a0e8acd3823e1caab30 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 00:32:38 -0700 Subject: [PATCH 03/31] Fixing some bugs, tweaking some strings for COTW --- .../java/com/gmail/nossr50/config/Config.java | 1 - .../nossr50/skills/taming/TamingManager.java | 44 ++++++++++++------- .../skills/taming/TrackedTamingEntity.java | 3 +- .../nossr50/util/skills/CombatUtils.java | 1 - .../resources/locale/locale_en_US.properties | 4 +- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 692ae055c..d16ab6852 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.util.StringUtils; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.EntityType; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 9d55c6057..45b58e919 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -27,7 +27,6 @@ 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.Sound; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; @@ -86,7 +85,7 @@ public class TamingManager extends SkillManager { for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { Material itemSummonMaterial = Config.getInstance().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); - int itemAmountRequired = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int itemAmountRequired = Config.getInstance().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); int entitiesSummonedPerCOTW = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); int summonLifespanSeconds = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); int perPlayerMaxAmount = Config.getInstance().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); @@ -333,6 +332,8 @@ public class TamingManager extends SkillManager { CallOfTheWildType callOfTheWildType = summoningItems.get(itemInMainHand.getType()); TamingSummon tamingSummon = cotwSummonDataProperties.get(callOfTheWildType); + //Players will pay for the cost if at least one thing was summoned + int amountSummoned = 0; //Check to see if players have the correct amount of the item required to summon if(itemInMainHand.getAmount() >= tamingSummon.getItemAmountRequired()) { @@ -343,30 +344,37 @@ public class TamingManager extends SkillManager { for (int i = 0; i < tamingSummon.getEntitiesSummoned(); i++) { if (getAmountCurrentlySummoned(callOfTheWildType) >= tamingSummon.getSummonCap()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Taming.Summon.COTW.Limit", String.valueOf(tamingSummon.getSummonCap())); + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Limit", + String.valueOf(tamingSummon.getSummonCap()), + StringUtils.getCapitalized(callOfTheWildType.toString())); break; } spawnLocation = Misc.getLocationOffset(spawnLocation, 1); spawnCOTWEntity(callOfTheWildType, spawnLocation, tamingSummon.getEntityType()); + + //Inform the player about what they have just done + if (tamingSummon.getSummonLifespan() > 0) { + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success", + StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan())); + } else { + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.Complete"); + } + + //Send Sound + SoundManager.sendSound(player, player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + + amountSummoned++; } - //Remove the items used to summon - int itemAmountAfterPayingCost = itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired(); - itemInMainHand.setAmount(itemAmountAfterPayingCost); - player.updateInventory(); - - //Inform the player about what they have just done - if (tamingSummon.getSummonLifespan() > 0) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.COTW.Success", - StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan())); - } else { - NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.Complete"); + //Remove items from the player if they had at least one entity summoned successfully + if(amountSummoned >= 1) { + //Remove the items used to summon + int itemAmountAfterPayingCost = itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired(); + itemInMainHand.setAmount(itemAmountAfterPayingCost); + player.updateInventory(); } - //Send Sound - SoundManager.sendSound(player, player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); - } else { //Player did not have enough of the item in their main hand int difference = tamingSummon.getItemAmountRequired() - itemInMainHand.getAmount(); @@ -449,6 +457,7 @@ public class TamingManager extends SkillManager { horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); + //TODO: setSpeed, once available callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.HORSE))); @@ -546,6 +555,7 @@ public class TamingManager extends SkillManager { //Remove from existence if(livingEntity != null && livingEntity.isValid()) { + livingEntity.setHealth(0); livingEntity.remove(); } } diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 6028d97c4..0a8e99637 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -4,12 +4,10 @@ import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.LivingEntity; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.scheduler.BukkitRunnable; import java.util.UUID; @@ -45,6 +43,7 @@ public class TrackedTamingEntity extends BukkitRunnable { if(tamingManagerRef != null) tamingManagerRef.removeFromTracker(this); + livingEntity.setHealth(0); livingEntity.remove(); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index cd3ffb75a..598310e41 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; import com.gmail.nossr50.skills.swords.SwordsManager; import com.gmail.nossr50.skills.taming.TamingManager; -import com.gmail.nossr50.skills.unarmed.Unarmed; import com.gmail.nossr50.skills.unarmed.UnarmedManager; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index e8ad00393..ff84cff18 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -484,8 +484,8 @@ Taming.Summon.Complete=[[GREEN]]Summoning complete Taming.Summon.COTW.Success=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] and it has a duration of [[GOLD]]{1}[[GRAY]] seconds. Taming.Summon.Lifespan= (Lifespan: {0}s) Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0}) -Taming.Summon.COTW.Limit=[[RED]]You can only summon up to {0} for this type of animal. Try again later. -Taming.Summon.COTW.TimeExpired=[[GREEN]](Call Of The Wild) [[GRAY]]Time is up, your temporary summon [[GOLD]]{0}[[GRAY]] departs. +Taming.Summon.COTW.Limit=[[GREEN]](Call Of The Wild) [[GRAY]]You can only have [[RED]]{0} [[GRAY]]summoned [[GRAY]]{1} pets at the same time. +Taming.Summon.COTW.TimeExpired=[[GREEN]](Call Of The Wild) [[GRAY]]Time is up, your [[GOLD]]{0}[[GRAY]] departs. Taming.Summon.COTW.BreedingDisallowed=[[GREEN]](Call Of The Wild) [[RED]]You cannot breed a summoned animal. Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0}'s {1} #UNARMED From 8a9c83606524a21af76ef3a2c1e0c78788d1cecf Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 00:45:08 -0700 Subject: [PATCH 04/31] More locale tweaks for COTW --- Changelog.txt | 7 ++++++- .../com/gmail/nossr50/skills/taming/TamingManager.java | 7 +++---- src/main/resources/locale/locale_en_US.properties | 7 +++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 27f661da5..3ad695e07 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,6 @@ Version 2.1.92 Call Of The Wild (COTW) no longer cares if entities of the same type are nearby when attempting to summon a new entity + Most COTW messages have been tweaked and new COTW messages have been added By default players are no longer allowed to breed COTW summoned animals with other animals, you can turn this off (see the notes) Changed the sound effect for COTW (Fireworks -> Pop) Fixed a bug where COTW summon limit was global instead of per player @@ -18,9 +19,13 @@ Version 2.1.92 Taming.Summon.Fail.Ocelot Taming.Summon.Fail.Wolf Taming.Summon.Fail.Horse + Taming.Summon.Fail.TooMany + Taming.Summon.Lifespan Added new locale strings + Taming.Summon.COTW.NeedMoreItems Taming.Summon.COTW.BreedingDisallowed - Taming.Summon.COTW.Success + Taming.Summon.COTW.Success.WithLifespan + Taming.Summon.COTW.Success.WithoutLifespan Taming.Summon.COTW.Limit Taming.Summon.COTW.TimeExpired Tweaked locale string diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 45b58e919..735c8d3c0 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -355,10 +355,10 @@ public class TamingManager extends SkillManager { //Inform the player about what they have just done if (tamingSummon.getSummonLifespan() > 0) { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success", + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success.WithLifespan", StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan())); } else { - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.Complete"); + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.Success.WithoutLifespan", StringUtils.getCapitalized(callOfTheWildType.toString())); } //Send Sound @@ -378,10 +378,9 @@ public class TamingManager extends SkillManager { } else { //Player did not have enough of the item in their main hand int difference = tamingSummon.getItemAmountRequired() - itemInMainHand.getAmount(); - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.NotEnough", String.valueOf(difference), StringUtils.getPrettyItemString(itemInMainHand.getType())); + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.NeedMoreItems", String.valueOf(difference), StringUtils.getPrettyItemString(itemInMainHand.getType())); } } - } private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) { diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index ff84cff18..7b6b75b7c 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -480,13 +480,12 @@ Taming.SubSkill.Pummel.TargetMessage=You've been knocked back by a wolf! Taming.Listener.Wolf=[[DARK_GRAY]]Your wolf scurries back to you... Taming.Listener=Taming: Taming.SkillName=TAMING -Taming.Summon.Complete=[[GREEN]]Summoning complete -Taming.Summon.COTW.Success=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] and it has a duration of [[GOLD]]{1}[[GRAY]] seconds. -Taming.Summon.Lifespan= (Lifespan: {0}s) -Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0}) +Taming.Summon.COTW.Success.WithoutLifespan=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] +Taming.Summon.COTW.Success.WithLifespan=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] and it has a duration of [[GOLD]]{1}[[GRAY]] seconds. Taming.Summon.COTW.Limit=[[GREEN]](Call Of The Wild) [[GRAY]]You can only have [[RED]]{0} [[GRAY]]summoned [[GRAY]]{1} pets at the same time. Taming.Summon.COTW.TimeExpired=[[GREEN]](Call Of The Wild) [[GRAY]]Time is up, your [[GOLD]]{0}[[GRAY]] departs. Taming.Summon.COTW.BreedingDisallowed=[[GREEN]](Call Of The Wild) [[RED]]You cannot breed a summoned animal. +Taming.Summon.COTW.NeedMoreItems=[[GREEN]](Call Of The Wild) [[GRAY]]You need [[YELLOW]]{0}[[GRAY]] more [[DARK_AQUA]]{1}[[GRAY]](s) Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0}'s {1} #UNARMED Unarmed.Ability.Bonus.0=Iron Arm Style From 444edb209c0e2b984c411eaa085e81ed7b9fdee4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 01:14:11 -0700 Subject: [PATCH 05/31] Remove summoned entities on server shutdown --- Changelog.txt | 1 + src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java | 1 + src/main/java/com/gmail/nossr50/util/player/UserManager.java | 1 + 3 files changed, 3 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 3ad695e07..d1f1b014e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,7 @@ Version 2.1.92 Call Of The Wild (COTW) no longer cares if entities of the same type are nearby when attempting to summon a new entity Most COTW messages have been tweaked and new COTW messages have been added + COTW Horses now always spawn in as adults By default players are no longer allowed to breed COTW summoned animals with other animals, you can turn this off (see the notes) Changed the sound effect for COTW (Fireworks -> Pop) Fixed a bug where COTW summon limit was global instead of per player diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 735c8d3c0..ca898856b 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -456,6 +456,7 @@ public class TamingManager extends SkillManager { horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); + horse.setAdult(); //TODO: setSpeed, once available diff --git a/src/main/java/com/gmail/nossr50/util/player/UserManager.java b/src/main/java/com/gmail/nossr50/util/player/UserManager.java index b2044766c..396770c58 100644 --- a/src/main/java/com/gmail/nossr50/util/player/UserManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/UserManager.java @@ -44,6 +44,7 @@ public final class UserManager { */ public static void remove(Player player) { McMMOPlayer mcMMOPlayer = getPlayer(player); + mcMMOPlayer.cleanup(); player.removeMetadata(mcMMO.playerDataKey, mcMMO.p); if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer)) { From 1ae9e80d963f968440e232be9fc9e037c8dbb619 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 01:31:49 -0700 Subject: [PATCH 06/31] Prevent spam from breeding events --- .../java/com/gmail/nossr50/listeners/EntityListener.java | 9 ++++++++- src/main/resources/locale/locale_en_US.properties | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index b69dc4a83..b232f18c0 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -72,6 +72,8 @@ public class EntityListener implements Listener { if(!ExperienceConfig.getInstance().isEndermanEndermiteFarmingPrevented()) return; + if(event.getReason() == EntityTargetEvent.TargetReason.TEMPT) + //It's rare but targets can be null sometimes if(event.getTarget() == null) { @@ -683,7 +685,7 @@ public class EntityListener implements Listener { * @param event * The event to watch */ - @EventHandler(priority = EventPriority.MONITOR) + @EventHandler(ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent event) { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) @@ -739,6 +741,11 @@ public class EntityListener implements Listener { if(ExperienceConfig.getInstance().isCOTWBreedingPrevented()) { if(event.getFather().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON) || event.getMother().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON)) { event.setCancelled(true); + Animals mom = (Animals) event.getMother(); + Animals father = (Animals) event.getFather(); + + mom.setLoveModeTicks(0); + father.setLoveModeTicks(0); } if(event.getBreeder() instanceof Player) { diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 7b6b75b7c..5f6dea6e5 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -929,7 +929,7 @@ Guides.Swords.Section.2=[[DARK_AQUA]]How does Counter Attack work?\n[[YELLOW]]Co Guides.Swords.Section.3=[[DARK_AQUA]]How does Rupture work?\n[[YELLOW]]Rupture causes enemies to take damage every two seconds. The \n[[YELLOW]]target will bleed until the effect wears off, or death, \n[[YELLOW]]whichever comes first.\n[[YELLOW]]The duration of the bleed is increased by your sword skill. ##Taming Guides.Taming.Section.0=[[DARK_AQUA]]About Taming:\n[[YELLOW]]Taming will give players various combat bonuses when using\n[[YELLOW]]tamed wolves.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you need to tame wolves/ocelots or\n[[YELLOW]]get into combat with your wolves. -Guides.Taming.Section.1=[[DARK_AQUA]]How does Call of the Wild work?\n[[YELLOW]]Call of the Wild is an active ability that will allow you to summon\n[[YELLOW]]a wolf or an ocelot by your side. You can do this by\n[[YELLOW]]left-clicking while holding bones or fish. +Guides.Taming.Section.1=[[DARK_AQUA]]How does Call of the Wild work?\n[[YELLOW]]Call of the Wild is an active ability that will allow you to summon\n[[YELLOW]]a wolf or an ocelot by your side. You can do this by\n[[YELLOW]]sneaking + left-clicking while holding bones or fish. Guides.Taming.Section.2=[[DARK_AQUA]]How does Beast Lore work?\n[[YELLOW]]Beast Lore allows players to inspect pets and to check the\n[[YELLOW]]stats of wolves and ocelots. Left-click a wolf or ocelot to use\n[[YELLOW]]Beast Lore. Guides.Taming.Section.3=[[DARK_AQUA]]How does Gore work?\n[[YELLOW]]Gore is a passive ability that has a chance of inflicting a\n[[YELLOW]]bleeding effect on your wolves' targets. Guides.Taming.Section.4=[[DARK_AQUA]]How does Sharpened Claws work?\n[[YELLOW]]Sharpened Claws provides a damage bonus to damage dealt\n[[YELLOW]]by wolves. The damage bonus depends on your Taming level. From 6e70258f9a993fc3f0f85fb7f80c379ade5d0856 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 01:44:01 -0700 Subject: [PATCH 07/31] 2.1.92 --- Changelog.txt | 19 ++++++++++--------- pom.xml | 2 +- .../nossr50/skills/taming/TamingManager.java | 3 +++ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index d1f1b014e..4e2a1aaed 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,18 +1,19 @@ Version 2.1.92 Call Of The Wild (COTW) no longer cares if entities of the same type are nearby when attempting to summon a new entity - Most COTW messages have been tweaked and new COTW messages have been added - COTW Horses now always spawn in as adults - By default players are no longer allowed to breed COTW summoned animals with other animals, you can turn this off (see the notes) - Changed the sound effect for COTW (Fireworks -> Pop) Fixed a bug where COTW summon limit was global instead of per player - The default summon limit for COTW is now per player instead of global which is how it is intended to be, for wolves this defaults to 2, for other entities it defaults to 1 - There is now a small 150ms window in which you cannot summon an entity via COTW to prevent accidentally summoning extra entities - The setting named Summon_Max_Amount in config.yml has been renamed to Per_Player_Limit - COTW entities now send the player a message when they die, time out, or get removed through other means + If you are playing in 1.14 mcMMO will now summon cats instead of ocelots + The default summon limit for COTW is now per player instead of global which is how it should be, for wolves this defaults to 2, for other entities it defaults to 1 + The COTW setting named Summon_Max_Amount in config.yml has been renamed to Per_Player_Limit + By default players are no longer allowed to breed COTW summoned animals with other animals, you can turn this off (see the notes) + If a player tries to breed animals with a COTW animal and the server settings prevent this, they are informed via a message that it is not allowed If the COTW summon has a lifespan, players are now informed about this lifespan when the entity is first summoned + COTW entities now send the player a message when they die, time out, or get removed through other means COTW summons now have their name prefixed with some colored text to to make it easier to identify them. COTW summons now despawn if their owner logs out - If a player tries to breed animals with a COTW animal and the server settings prevent this, they are informed via a message that it is not allowed + There is now a small 150ms window in which you cannot summon an entity via COTW to prevent accidentally summoning extra entities + COTW Horses, Cats, and Wolves now always spawn in as adults + Changed the sound effect for COTW (Fireworks -> Pop) + Most COTW messages have been tweaked and new COTW messages have been added Added new setting to experience.yml 'ExploitFix.COTWBreeding' - Prevents breeding with COTW summoned entities when set to true, defaults to true Removed the 'mcmmo.ability.taming.callofthewild.renamepets' permission node as it is seen as unnecessary diff --git a/pom.xml b/pom.xml index b19452d2c..918e67c92 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.92-SNAPSHOT + 2.1.92 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index ca898856b..bd5ab8cd4 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -406,6 +406,7 @@ public class TamingManager extends SkillManager { setBaseCOTWEntityProperties(callOfWildEntity); + ((Wolf) callOfWildEntity).setAdult(); addToTracker(callOfWildEntity, CallOfTheWildType.WOLF); //Setup wolf stats @@ -429,9 +430,11 @@ public class TamingManager extends SkillManager { if(callOfWildEntity instanceof Ocelot) { int numberOfTypes = Ocelot.Type.values().length; ((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); + ((Ocelot) callOfWildEntity).setAdult(); } else if(callOfWildEntity instanceof Cat) { int numberOfTypes = Cat.Type.values().length; ((Cat) callOfWildEntity).setCatType(Cat.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]); + ((Cat) callOfWildEntity).setAdult(); } callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(entityType))); From bf70a42f6a0acb9e60e0ba6d443c90f752839586 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 12:45:25 -0700 Subject: [PATCH 08/31] Fix breeding sending incorrect messages --- Changelog.txt | 3 +++ pom.xml | 2 +- .../com/gmail/nossr50/listeners/EntityListener.java | 11 +++++++---- src/main/resources/plugin.yml | 3 --- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 4e2a1aaed..0da17bf62 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.93 + Fixed a bug where players would be told they could not breed summoned animals when the animals weren't summoned (bug didn't actually do anything besides send you a message) + Version 2.1.92 Call Of The Wild (COTW) no longer cares if entities of the same type are nearby when attempting to summon a new entity Fixed a bug where COTW summon limit was global instead of per player diff --git a/pom.xml b/pom.xml index 918e67c92..efde8132c 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.92 + 2.1.93-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index b232f18c0..ec004949a 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -744,14 +744,17 @@ public class EntityListener implements Listener { Animals mom = (Animals) event.getMother(); Animals father = (Animals) event.getFather(); + //Prevent love mode spam mom.setLoveModeTicks(0); father.setLoveModeTicks(0); + + //Inform the player + if(event.getBreeder() instanceof Player) { + Player player = (Player) event.getBreeder(); + NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.BreedingDisallowed"); + } } - if(event.getBreeder() instanceof Player) { - Player player = (Player) event.getBreeder(); - NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.BreedingDisallowed"); - } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ae9061bcc..e29bef197 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -616,14 +616,11 @@ permissions: children: mcmmo.ability.taming.callofthewild.horse: true mcmmo.ability.taming.callofthewild.ocelot: true - mcmmo.ability.taming.callofthewild.renamepets: true mcmmo.ability.taming.callofthewild.wolf: true mcmmo.ability.taming.callofthewild.horse: description: Allows players to summon Horses with Call of the Wild mcmmo.ability.taming.callofthewild.ocelot: description: Allows players to summon Ocelots with Call of the Wild - mcmmo.ability.taming.callofthewild.renamepets: - description: Allows players to rename pets with Call of the Wild mcmmo.ability.taming.callofthewild.wolf: description: Allows players to summon Wolves with Call of the Wild mcmmo.ability.taming.environmentallyaware: From 5d0ce407b7b268807e776caa54da9c6a22b7cad9 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 13:47:37 -0700 Subject: [PATCH 09/31] 2.1.93 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index efde8132c..d9949935f 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.93-SNAPSHOT + 2.1.93 mcMMO https://github.com/mcMMO-Dev/mcMMO From 6e00f7eaa2b609ab1de7b09df9975aa1828a88bc Mon Sep 17 00:00:00 2001 From: SNAKE0053 <6961187+snake0053@users.noreply.github.com> Date: Wed, 3 Jul 2019 06:41:29 +0900 Subject: [PATCH 10/31] Update locale_ja_JP.properties --- .../resources/locale/locale_ja_JP.properties | 87 ++++++++++--------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/src/main/resources/locale/locale_ja_JP.properties b/src/main/resources/locale/locale_ja_JP.properties index a36c97d4e..aed00e575 100644 --- a/src/main/resources/locale/locale_ja_JP.properties +++ b/src/main/resources/locale/locale_ja_JP.properties @@ -139,7 +139,7 @@ Alchemy.SubSkill.Concoctions.Description=\u3082\u3063\u3068\u6750\u6599\u3092\u5 Alchemy.SubSkill.Concoctions.Stat=\u8abf\u5408 \u30e9\u30f3\u30af: [[GREEN]]{0}[[DARK_AQUA]]/[[GREEN]]{1} Alchemy.SubSkill.Concoctions.Stat.Extra=\u6750\u6599 [[[GREEN]]{0}[[DARK_AQUA]]]: [[GREEN]]{1} Alchemy.Listener=\u932c\u91d1\u8853: -Alchemy.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u89e6\u5a92\u4f5c\u7528) +Alchemy.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u89e6\u5a92\u4f5c\u7528) Alchemy.SkillName=\u932c\u91d1\u8853 #ARCHERY @@ -203,6 +203,11 @@ Excavation.SubSkill.GigaDrillBreaker.Description=3x \u30c9\u30ed\u30c3\u30d7\u73 Excavation.SubSkill.GigaDrillBreaker.Stat=\u30ae\u30ac\u30c9\u30ea\u30eb\u30d6\u30ec\u30fc\u30ab\u30fc \u671f\u9593 Excavation.SubSkill.Archaeology.Name=\u8003\u53e4\u5b66 Excavation.SubSkill.Archaeology.Description=\u571f\u5730\u306b\u96a0\u308c\u305f\u7269\u3092\u6398\u308a\u51fa\u3059\uff01 +Excavation.SubSkill.Archaeology.Name=\u8003\u53e4\u5b66 +Excavation.SubSkill.Archaeology.Description=\u5b9d\u3092\u767a\u6398\u3057\u3088\u3046\uff01\u30b9\u30ad\u30eb\u30ec\u30d9\u30eb\u304c\u9ad8\u3044\u3068\u3001\u5b9d\u3092\u898b\u3064\u3051\u305f\u3068\u304d\u306b\u7d4c\u9a13\u5024\u30aa\u30fc\u30d6\u3092\u898b\u3064\u3051\u308b\u53ef\u80fd\u6027\u304c\u9ad8\u304f\u306a\u308a\u307e\u3059\u3002 +Excavation.SubSkill.Archaeology.Stat=\u8003\u53e4\u5b66 \u7d4c\u9a13\u5024\u30aa\u30fc\u30d6\u767a\u898b\u78ba\u7387 +Excavation.SubSkill.Archaeology.Stat.Extra=\u8003\u53e4\u5b66 \u7d4c\u9a13\u5024\u30aa\u30fc\u30d6\u91cf + Excavation.Listener=\u6398\u524a: Excavation.SkillName=\u6398\u524a Excavation.Skills.GigaDrillBreaker.Off=**\u30ae\u30ac\u30c9\u30ea\u30eb\u30d6\u30ec\u30fc\u30ab\u30fc \u3092\u6469\u640d\u3057\u305f** @@ -217,9 +222,9 @@ Fishing.Scared=[[GRAY]]&o\u6df7\u6c8c\u3068\u3057\u305f\u52d5\u304d\u306f\u9b5a\ Fishing.Exhausting=[[RED]]&o\u91e3\u308a\u7aff\u3092\u4e0d\u9069\u5207\u306b\u4f7f\u7528\u3059\u308b\u3068\u3001\u75b2\u52b4\u3092\u5f15\u304d\u8d77\u3053\u3057\u305f\u308a\u3001\u8010\u4e45\u5024\u3092\u6d88\u8cbb\u3057\u305f\u308a\u3057\u307e\u3059\u3002 Fishing.LowResourcesTip=[[GRAY]]\u3053\u306e\u5730\u57df\u306b\u3044\u308b\u9b5a\u304c\u305d\u308c\u307b\u3069\u591a\u304f\u306a\u3044\u3053\u3068\u3092\u611f\u3058\u307e\u3057\u305f\u3002\u5c11\u306a\u304f\u3068\u3082{0}\u30d6\u30ed\u30c3\u30af\u96e2\u308c\u305f\u3068\u3053\u308d\u3067\u91e3\u308a\u3092\u3057\u3066\u307f\u3066\u4e0b\u3055\u3044\u3002 Fishing.Ability.Info=\u30de\u30b8\u30c3\u30af\u30cf\u30f3\u30bf\u30fc: [[GRAY]] **\u30c8\u30ec\u30b8\u30e3\u30fc\u30cf\u30f3\u30bf\u30fc \u30e9\u30f3\u30af\u3067\u6539\u5584\u3059\u308b** -Fishing.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u30b7\u30a7\u30a4\u30af) -Fishing.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (\u7a74\u91e3\u308a) -Fishing.Ability.Locked.2=LOCKED UNTIL {0}+ SKILL (\u30de\u30b9\u30bf\u30fc\u30a2\u30f3\u30b0\u30e9\u30fc) +Fishing.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30b7\u30a7\u30a4\u30af) +Fishing.Ability.Locked.1=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u7a74\u91e3\u308a) +Fishing.Ability.Locked.2=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30de\u30b9\u30bf\u30fc\u30a2\u30f3\u30b0\u30e9\u30fc) Fishing.SubSkill.TreasureHunter.Name=\u30c8\u30ec\u30b8\u30e3\u30fc\u30cf\u30f3\u30bf\u30fc Fishing.SubSkill.TreasureHunter.Description=\u9b5a\u3084\u7269\u3092\u91e3\u308a\u4e0a\u3052\u308b\u3002 Fishing.SubSkill.TreasureHunter.Stat=\u30c8\u30ec\u30b8\u30e3\u30fc\u30cf\u30f3\u30bf\u30fc \u30e9\u30f3\u30af: [[GREEN]]{0}[[DARK_AQUA]]/[[GREEN]]{1} @@ -284,9 +289,9 @@ Herbalism.Skills.GTe.Other.Off=[[YELLOW]]{0}\u304c [[WHITE]]\u304c\u3059\u308a\u Herbalism.Skills.GTe.Other.On=[[GREEN]]{0}[[DARK_GREEN]]\u304c [[RED]]\u30b0\u30ea\u30fc\u30f3\u30c6\u30e9 [[DARK_GREEN]]\u3092\u4f7f\u3063\u305f\uff01 #MINING -Mining.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u30d6\u30e9\u30b9\u30c8\u30de\u30a4\u30cb\u30f3\u30b0) -Mining.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (\u5927\u304d\u306a\u7206\u5f3e) -Mining.Ability.Locked.2=LOCKED UNTIL {0}+ SKILL (\u89e3\u4f53\u5c02\u9580\u77e5\u8b58) +Mining.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30d6\u30e9\u30b9\u30c8\u30de\u30a4\u30cb\u30f3\u30b0) +Mining.Ability.Locked.1=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u5927\u304d\u306a\u7206\u5f3e) +Mining.Ability.Locked.2=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u89e3\u4f53\u5c02\u9580\u77e5\u8b58) Mining.Ability.Lower=[[GRAY]]\u30d4\u30c3\u30b1\u30eb\u3092\u4e0b\u3052\u305f\u3002 Mining.Ability.Ready=[[DARK_AQUA]]\u30d4\u30c3\u30b1\u30eb\u3092[[GOLD]]\u6e96\u5099[[DARK_AQUA]]\u3057\u305f\u3002 Mining.SubSkill.SuperBreaker.Name=\u30b9\u30fc\u30d1\u30fc\u30d6\u30ec\u30fc\u30ab\u30fc @@ -441,12 +446,12 @@ Taming.Ability.Bonus.8=\u30d5\u30a1\u30fc\u30b9\u30c8\u30d5\u30fc\u30c9\u30b5\u3 Taming.Ability.Bonus.9={0} \u306e\u78ba\u7387\u3067\u653b\u6483\u6642\u56de\u5fa9 Taming.Ability.Bonus.10=\u30db\u30fc\u30ea\u30fc\u30cf\u30a6\u30f3\u30c9 Taming.Ability.Bonus.11=\u9b54\u6cd5\u3084\u6bd2\u3067\u30c0\u30e1\u30fc\u30b8\u3092\u53d7\u3051\u305f\u6642\u72b6\u614b\u7570\u5e38\u3092\u53d6\u308a\u6d88\u3059\u3002 -Taming.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u74b0\u5883\u914d\u616e) -Taming.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (\u539a\u3044\u6bdb\u76ae) -Taming.Ability.Locked.2=LOCKED UNTIL {0}+ SKILL (\u885d\u6483\u8010\u6027) -Taming.Ability.Locked.3=LOCKED UNTIL {0}+ SKILL (\u92ed\u3044\u722a) -Taming.Ability.Locked.4=LOCKED UNTIL {0}+ SKILL (\u30d5\u30a1\u30fc\u30b9\u30c8\u30d5\u30fc\u30c9\u30b5\u30fc\u30d3\u30b9) -Taming.Ability.Locked.5=LOCKED UNTIL {0}+ SKILL (\u30db\u30fc\u30ea\u30fc\u30cf\u30a6\u30f3\u30c9) +Taming.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u74b0\u5883\u914d\u616e) +Taming.Ability.Locked.1=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u539a\u3044\u6bdb\u76ae) +Taming.Ability.Locked.2=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u885d\u6483\u8010\u6027) +Taming.Ability.Locked.3=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u92ed\u3044\u722a) +Taming.Ability.Locked.4=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30d5\u30a1\u30fc\u30b9\u30c8\u30d5\u30fc\u30c9\u30b5\u30fc\u30d3\u30b9) +Taming.Ability.Locked.5=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30db\u30fc\u30ea\u30fc\u30cf\u30a6\u30f3\u30c9) Taming.Combat.Chance.Gore=\u30b4\u30a2 \u78ba\u7387 Taming.SubSkill.BeastLore.Name=\u30d3\u30fc\u30b9\u30c8\u30ed\u30a2 Taming.SubSkill.BeastLore.Description=\u72fc\u3068\u732b\u3092\u9aa8\u3067\u691c\u67fb\u3059\u308b\u3002 @@ -473,13 +478,13 @@ Taming.SubSkill.Pummel.TargetMessage=\u72fc\u306b\u30ce\u30c3\u30af\u30d0\u30c3\ Taming.Listener.Wolf=[[DARK_GRAY]]\u72fc\u306f\u3042\u306a\u305f\u306e\u3082\u3068\u306b\u6025\u3044\u3067\u623b\u308a\u307e\u3059... Taming.Listener=\u8abf\u6559: Taming.SkillName=\u8abf\u6559 -Taming.Summon.Complete=[[GREEN]]\u53ec\u559a\u5b8c\u4e86 -Taming.Summon.Lifespan= (\u5bff\u547d: {0}\u79d2) -Taming.Summon.Fail.Ocelot=[[RED]]\u8fd1\u304f\u306b\u732b\u304c\u305f\u304f\u3055\u3093\u3044\u308b\u305f\u3081\u3053\u308c\u4ee5\u4e0a\u53ec\u559a\u3067\u304d\u307e\u305b\u3093\u3002 -Taming.Summon.Fail.Wolf=[[RED]]\u8fd1\u304f\u306b\u72fc\u304c\u305f\u304f\u3055\u3093\u3044\u308b\u305f\u3081\u3053\u308c\u4ee5\u4e0a\u53ec\u559a\u3067\u304d\u307e\u305b\u3093\u3002 -Taming.Summon.Fail.Horse=[[RED]]\u8fd1\u304f\u306b\u99ac\u304c\u305f\u304f\u3055\u3093\u3044\u308b\u305f\u3081\u3053\u308c\u4ee5\u4e0a\u53ec\u559a\u3067\u304d\u307e\u305b\u3093\u3002 -Taming.Summon.Fail.TooMany=[[RED]]\u53ec\u559a\u3067\u304d\u308b\u30da\u30c3\u30c8\u306e\u4e0a\u9650\u6570\u306b\u9054\u3057\u307e\u3057\u305f\u3002 [[YELLOW]]({0}) -Taming.Summon.Name.Format={0}\u306e{1} +Taming.Summon.COTW.Success.WithoutLifespan=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[GRAY]]\u3042\u306a\u305f\u306f[[GOLD]]{0}[[GRAY]]\u3092\u53ec\u559a\u3057\u307e\u3057\u305f[[GRAY]] +Taming.Summon.COTW.Success.WithLifespan=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[GOLD]]{0}[[GRAY]]\u3092\u53ec\u559a\u3057\u307e\u3057\u305f\u304c\u3001\u6301\u7d9a\u6642\u9593\u306f[[GOLD]]{1}[[GRAY]]\u79d2\u3067\u3059\u3002 +Taming.Summon.COTW.Limit=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[GOLD]]{0}[[GRAY]]\u306f\u540c\u6642\u306b[[GOLD]]{1}[[GRAY]]\u5339\u3057\u304b\u53ec\u559a\u3067\u304d\u307e\u305b\u3093\u3002 +Taming.Summon.COTW.TimeExpired=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[GRAY]]\u6642\u9593\u5207\u308c\u3067[[GOLD]]{0}[[GRAY]]\u304c\u7acb\u3061\u53bb\u308a\u307e\u3057\u305f\u3002 +Taming.Summon.COTW.BreedingDisallowed=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[RED]]\u53ec\u559a\u3055\u308c\u305f\u52d5\u7269\u3092\u7e41\u6b96\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002 +Taming.Summon.COTW.NeedMoreItems=[[GREEN]]\uff08\u91ce\u751f\u306e\u547c\u3073\u304b\u3051\uff09 [[YELLOW]]{0}[[GRAY]]\u304c[[DARK_AQUA]]{1}[[GRAY]]\u500b\u5fc5\u8981\u3067\u3059\u3002 +Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0} {1} #UNARMED Unarmed.Ability.Bonus.0=\u9244\u8155\u30b9\u30bf\u30a4\u30eb @@ -518,7 +523,7 @@ Unarmed.Skills.Berserk.Other.On=[[GREEN]]{0}[[DARK_GREEN]]\u304c [[RED]]\u30d0\u #WOODCUTTING Woodcutting.Ability.0=\u30ea\u30fc\u30d5\u30d6\u30ed\u30ef\u30fc Woodcutting.Ability.1=\u8449\u3092\u5439\u304d\u98db\u3070\u3059 -Woodcutting.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u30ea\u30fc\u30d5\u30d6\u30ed\u30ef\u30fc) +Woodcutting.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30ea\u30fc\u30d5\u30d6\u30ed\u30ef\u30fc) Woodcutting.SubSkill.TreeFeller.Name=\u30c4\u30ea\u30fc\u30d5\u30a7\u30e9\u30fc Woodcutting.SubSkill.TreeFeller.Description=\u6728\u3092\u7206\u767a\u3055\u305b\u308b\u3002 Woodcutting.SubSkill.TreeFeller.Stat=\u30c4\u30ea\u30fc\u30d5\u30a7\u30e9\u30fc \u9577\u3055 @@ -609,11 +614,11 @@ Party.Feature.Teleport=\u30d1\u30fc\u30c6\u30a3\u30fc\u30c6\u30ec\u30dd\u30fc\u3 Party.Feature.Alliance=\u540c\u76df Party.Feature.ItemShare=\u30a2\u30a4\u30c6\u30e0\u5171\u6709 Party.Feature.XpShare=XP\u5171\u6709 -Party.Feature.Locked.Chat=LOCKED UNTIL {0}+ (\u30d1\u30fc\u30c6\u30a3\u30fc\u30c1\u30e3\u30c3\u30c8) -Party.Feature.Locked.Teleport=LOCKED UNTIL {0}+ (\u30d1\u30fc\u30c6\u30a3\u30fc\u30c6\u30ec\u30dd\u30fc\u30c8) -Party.Feature.Locked.Alliance=LOCKED UNTIL {0}+ (\u540c\u76df) -Party.Feature.Locked.ItemShare=LOCKED UNTIL {0}+ (\u30a2\u30a4\u30c6\u30e0\u5171\u6709) -Party.Feature.Locked.XpShare=LOCKED UNTIL {0}+ (XP\u5171\u6709) +Party.Feature.Locked.Chat=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ (\u30d1\u30fc\u30c6\u30a3\u30fc\u30c1\u30e3\u30c3\u30c8) +Party.Feature.Locked.Teleport=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ (\u30d1\u30fc\u30c6\u30a3\u30fc\u30c6\u30ec\u30dd\u30fc\u30c8) +Party.Feature.Locked.Alliance=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ (\u540c\u76df) +Party.Feature.Locked.ItemShare=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ (\u30a2\u30a4\u30c6\u30e0\u5171\u6709) +Party.Feature.Locked.XpShare=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ (XP\u5171\u6709) Party.Feature.Disabled.1=[[RED]]\u30d1\u30fc\u30c6\u30a3\u30fc\u30c1\u30e3\u30c3\u30c8\u306f\u307e\u3060\u958b\u653e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 Party.Feature.Disabled.2=[[RED]]\u30d1\u30fc\u30c6\u30a3\u30fc\u30c6\u30ec\u30dd\u30fc\u30c8\u306f\u307e\u3060\u958b\u653e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 Party.Feature.Disabled.3=[[RED]]P\u540c\u76df\u306f\u307e\u3060\u958b\u653e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 @@ -692,26 +697,26 @@ Guides.Alchemy.Section.4=[[DARK_AQUA]]Concoctions tier 2 ingredients:\n[[YELLOW] Guides.Alchemy.Section.5=[[DARK_AQUA]]Concoctions tier 4 ingredients:\n[[YELLOW]]Apple (Potion of Health Boost)\n[[YELLOW]]Rotten Flesh (Potion of Hunger)\n\n[[DARK_AQUA]]Concoctions tier 5 ingredients:\n[[YELLOW]]Brown Mushroom (Potion of Nausea)\n[[YELLOW]]Ink Sack (Potion of Blindness) Guides.Alchemy.Section.6=[[DARK_AQUA]]Concoctions tier 6 ingredients:\n[[YELLOW]]Fern (Potion of Saturation)\n\n[[DARK_AQUA]]Concoctions tier 7 ingredients:\n[[YELLOW]]Poisonous Potato (Potion of Decay)\n\n[[DARK_AQUA]]Concoctions tier 8 ingredients:\n[[YELLOW]]Regular Golden Apple (Potion of Resistance) ##Archery -Guides.Archery.Section.0=[[DARK_AQUA]]About Archery:\n[[YELLOW]]Archery is about shooting with your bow and arrow.\n[[YELLOW]]It provides various combat bonuses, such as a damage boost\n[[YELLOW]]that scales with your level and the ability to daze your\n[[YELLOW]]opponents in PvP. In addition to this, you can retrieve\n[[YELLOW]]some of your spent arrows from the corpses of your foes.\n\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you need to shoot mobs or\n[[YELLOW]]other players. +Guides.Archery.Section.0=[[DARK_AQUA]]\u5f13\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Archery is about shooting with your bow and arrow.\n[[YELLOW]]It provides various combat bonuses, such as a damage boost\n[[YELLOW]]that scales with your level and the ability to daze your\n[[YELLOW]]opponents in PvP. In addition to this, you can retrieve\n[[YELLOW]]some of your spent arrows from the corpses of your foes.\n\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you need to shoot mobs or\n[[YELLOW]]other players. Guides.Archery.Section.1=[[DARK_AQUA]]How does Skill Shot work?\n[[YELLOW]]Skill Shot provides additional damage to your shots.\n[[YELLOW]]The bonus damage from Skill Shot increases as you\n[[YELLOW]]level in Archery.\n[[YELLOW]]With the default settings, your archery damage increases 10%\n[[YELLOW]]every 50 levels, to a maximum of 200% bonus damage. Guides.Archery.Section.2=[[DARK_AQUA]]How does Daze work?\n[[YELLOW]]You have a passive chance to daze other players when\n[[YELLOW]]you shoot them. When Daze triggers it forces your opponents\n[[YELLOW]]to look straight up for a short duration.\n[[YELLOW]]A Daze shot also deals an additional 4 damage (2 hearts). Guides.Archery.Section.3=[[DARK_AQUA]]How does Arrow Retrieval work?\n[[YELLOW]]You have a passive chance to retrieve some of your arrows\n[[YELLOW]]when you kill a mob with your bow.\n[[YELLOW]]This chance increases as you level in Archery.\n[[YELLOW]]By default, this ability increases by 0.1% per level, up to 100%\n[[YELLOW]]at level 1000. ##Axes -Guides.Axes.Section.0=[[DARK_AQUA]]About Axes:\n[[YELLOW]]With the Axes skill you can use your axe for much more then\n[[YELLOW]]just deforesting! You can hack and chop away at mobs\n[[YELLOW]]and players to gain XP, hitting mobs with the effect of\n[[YELLOW]]knockback and inflicting DEADLY criticals on mobs and players.\n[[YELLOW]]Your axe also becomes a hand-held woodchipper,\n[[YELLOW]]breaking down the enemy's armor with ease as your level\n[[YELLOW]]increases.\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you need hit other mobs or players\n[[YELLOW]]with an Axe. +Guides.Axes.Section.0=[[DARK_AQUA]]\u65a7\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]With the Axes skill you can use your axe for much more then\n[[YELLOW]]just deforesting! You can hack and chop away at mobs\n[[YELLOW]]and players to gain XP, hitting mobs with the effect of\n[[YELLOW]]knockback and inflicting DEADLY criticals on mobs and players.\n[[YELLOW]]Your axe also becomes a hand-held woodchipper,\n[[YELLOW]]breaking down the enemy's armor with ease as your level\n[[YELLOW]]increases.\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you need hit other mobs or players\n[[YELLOW]]with an Axe. Guides.Axes.Section.1=[[DARK_AQUA]]How does Skull Splitter work?\n[[YELLOW]]This ability allows you to deal an AoE (Area of Effect) hit.\n[[YELLOW]]This AoE hit will deal half as much damage as you did to the\n[[YELLOW]]main target, so it's great for clearing out large piles of mobs. Guides.Axes.Section.2=[[DARK_AQUA]]How does Critical Strikes work?\n[[YELLOW]]Critical Strikes is a passive ability which gives players a\n[[YELLOW]]chance to deal additional damage.\n[[YELLOW]]With the default settings, every 2 skill levels in Axes awards a\n[[YELLOW]]0.1% chance to deal a Critical Strike, causing 2.0 times damage\n[[YELLOW]]to mobs or 1.5 times damage against other players. Guides.Axes.Section.3=[[DARK_AQUA]]How does Axe Mastery work?\n[[YELLOW]]Axe Mastery is a passive ability that will add additional damage\n[[YELLOW]]to your hits when using Axes.\n[[YELLOW]]By default, the bonus damage increases by 1 every 50 levels,\n[[YELLOW]]up to a cap of 4 extra damage at level 200. Guides.Axes.Section.4=[[DARK_AQUA]]How does Armor Impact work?\n[[YELLOW]]Strike with enough force to shatter armor!\n[[YELLOW]]Armor Impact has a passive chance to damage your\n[[YELLOW]]opponent's armor. This damage increases as you level in Axes. Guides.Axes.Section.5=[[DARK_AQUA]]How does Greater Impact work?\n[[YELLOW]]You have a passive chance to achieve a greater impact when\n[[YELLOW]]hitting mobs or players with your axe.\n[[YELLOW]]By default this chance is 25%. This passive ability has an\n[[YELLOW]]extreme knockback effect, similar to the Knockback II\n[[YELLOW]]enchantment. In addition, it deals bonus damage to the target. ##Excavation -Guides.Excavation.Section.0=[[DARK_AQUA]]About Excavation:\n[[YELLOW]]Excavation is the act of digging up dirt to find treasures.\n[[YELLOW]]By excavating the land you will find treasures.\n[[YELLOW]]The more you do this the more treasures you can find.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you must dig with a shovel in hand.\n[[YELLOW]]Only certain materials can be dug up for treasures and XP. +Guides.Excavation.Section.0=[[DARK_AQUA]]\u6398\u524a\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Excavation is the act of digging up dirt to find treasures.\n[[YELLOW]]By excavating the land you will find treasures.\n[[YELLOW]]The more you do this the more treasures you can find.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill you must dig with a shovel in hand.\n[[YELLOW]]Only certain materials can be dug up for treasures and XP. Guides.Excavation.Section.1=[[DARK_AQUA]]Compatible Materials:\n[[YELLOW]]Grass, Dirt, Sand, Clay, Gravel, Mycelium, Soul Sand, Snow Guides.Excavation.Section.2=[[DARK_AQUA]]How to use Giga Drill Breaker:\n[[YELLOW]]With a shovel in hand right click to ready your tool.\n[[YELLOW]]Once in this state you have about 4 seconds to make\n[[YELLOW]]contact with Excavation compatible materials this will\n[[YELLOW]]activate Giga Drill Breaker. Guides.Excavation.Section.3=[[DARK_AQUA]]What is Giga Drill Breaker?\n[[YELLOW]]Giga Drill Breaker is an ability with a cooldown\n[[YELLOW]]tied to Excavation skill. It triples your chance\n[[YELLOW]]of finding treasures and enables instant break\n[[YELLOW]]on Excavation materials. Guides.Excavation.Section.4=[[DARK_AQUA]]How does Archaeology work?\n[[YELLOW]]Every possible treasure for Excavation has its own\n[[YELLOW]]skill level requirement for it to drop, as a result it's\n[[YELLOW]]difficult to say how much it is helping you.\n[[YELLOW]]Just keep in mind that the higher your Excavation skill\n[[YELLOW]]is, the more treasures that can be found.\n[[YELLOW]]And also keep in mind that each type of Excavation\n[[YELLOW]]compatible material has its own unique list of treasures.\n[[YELLOW]]In other words you will find different treasures in Dirt\n[[YELLOW]]than you would in Gravel. Guides.Excavation.Section.5=[[DARK_AQUA]]Notes about Excavation:\n[[YELLOW]]Excavation drops are completely customizeable\n[[YELLOW]]So results vary server to server. ##Fishing -Guides.Fishing.Section.0=[[DARK_AQUA]]About Fishing:\n[[YELLOW]]With the Fishing skill, Fishing is exciting again!\n[[YELLOW]]Find hidden treasures, and shake items off mobs.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Catch fish. +Guides.Fishing.Section.0=[[DARK_AQUA]]\u91e3\u308a\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]With the Fishing skill, Fishing is exciting again!\n[[YELLOW]]Find hidden treasures, and shake items off mobs.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Catch fish. Guides.Fishing.Section.1=[[DARK_AQUA]]How does Treasure Hunter work?\n[[YELLOW]]This ability allows you to find treasure from fishing \n[[YELLOW]]with a small chance of the items being enchanted.\n[[YELLOW]]Every possible treasure for Fishing has a chance\n[[YELLOW]]to drop on any level. It depends however\n[[YELLOW]]what the rarity of the item is how often it will drop.\n[[YELLOW]]The higher your Fishing skill is, the better\n[[YELLOW]]your chances are to find better treasures. Guides.Fishing.Section.2=[[DARK_AQUA]]How does Ice Fishing work?\n[[YELLOW]]This passive skill allows you to fish in ice lakes!\n[[YELLOW]]Cast your fishing rod in an ice lake and the ability will\n[[YELLOW]]create a small hole in the ice to fish in. Guides.Fishing.Section.3=[[DARK_AQUA]]How does Master Angler work?\n[[YELLOW]]This passive skill increases the bite chance while fishing.\n[[YELLOW]]When you've unlocked this ability, fishing while in\n[[YELLOW]]a boat or when an ocean biome doubles the bite chance. @@ -719,7 +724,7 @@ Guides.Fishing.Section.4=[[DARK_AQUA]]How does Shake work?\n[[YELLOW]]This activ Guides.Fishing.Section.5=[[DARK_AQUA]]How does Fisherman's Diet work?\n[[YELLOW]]This passive skill increases the amount of hunger restored \n[[YELLOW]]from eating fish. Guides.Fishing.Section.6=[[DARK_AQUA]]Notes about Fishing:\n[[YELLOW]]Fishing drops are completely customizable,\n[[YELLOW]]so results vary server to server. ##Herbalism -Guides.Herbalism.Section.0=[[DARK_AQUA]]About Herbalism:\n[[YELLOW]]Herbalism is about collecting herbs and plants.\n\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Collect plants and herbs. +Guides.Herbalism.Section.0=[[DARK_AQUA]]\u8fb2\u696d\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Herbalism is about collecting herbs and plants.\n\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Collect plants and herbs. Guides.Herbalism.Section.1=[[DARK_AQUA]]Compatible Blocks\n[[YELLOW]]Wheat, Potatoes, Carrots, Melons, \n[[YELLOW]]Pumpkins, Sugar Canes, Cocoa Beans, Flowers, Cacti, Mushrooms,\n[[YELLOW]]Nether Wart, Lily Pads, and Vines. Guides.Herbalism.Section.2=[[DARK_AQUA]]How does Green Terra work?\n[[YELLOW]]Green Terra is an active ability, you can right-click\n[[YELLOW]]while holding a hoe to activate Green Terra.\n[[YELLOW]]Green Terra grants players a chance to get 3x drops from\n[[YELLOW]]harvesting plants. It also gives players the ability to\n[[YELLOW]]spread life into blocks and transform them using seeds\n[[YELLOW]]from your inventory. Guides.Herbalism.Section.3=[[DARK_AQUA]]How does Green Thumb (Crops) work?\n[[YELLOW]]This passive ability will automatically replant crops when\n[[YELLOW]]harvesting.\n[[YELLOW]]Your chance of success depends on your Herbalism skill. @@ -728,20 +733,20 @@ Guides.Herbalism.Section.5=[[DARK_AQUA]]How does Farmer's Diet work?\n[[YELLOW]] Guides.Herbalism.Section.6=[[DARK_AQUA]]How does Hylian Luck work?\n[[YELLOW]]This passive ability gives you a chance to find rare items\n[[YELLOW]]when certain blocks are broken with a sword. Guides.Herbalism.Section.7=[[DARK_AQUA]]How do Double Drops work?\n[[YELLOW]]This passive ability gives players more yield from their\n[[YELLOW]]harvests. ##Mining -Guides.Mining.Section.0=[[DARK_AQUA]]About Mining:\n[[YELLOW]]Mining consists of mining stone and ores. It provides bonuses\n[[YELLOW]]to the amount of materials dropped while mining.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you must mine with a pickaxe in hand.\n[[YELLOW]]Only certain blocks award XP. +Guides.Mining.Section.0=[[DARK_AQUA]]\u63a1\u6398\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Mining consists of mining stone and ores. It provides bonuses\n[[YELLOW]]to the amount of materials dropped while mining.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you must mine with a pickaxe in hand.\n[[YELLOW]]Only certain blocks award XP. Guides.Mining.Section.1=[[DARK_AQUA]]Compatible Materials:\n[[YELLOW]]Stone, Coal Ore, Iron Ore, Gold Ore, Diamond Ore, Redstone Ore,\n[[YELLOW]]Lapis Ore, Obsidian, Mossy Cobblestone, Ender Stone,\n[[YELLOW]]Glowstone, and Netherrack. Guides.Mining.Section.2=[[DARK_AQUA]]How to use Super Breaker:\n[[YELLOW]]With a pickaxe in your hand, right click to ready your tool.\n[[YELLOW]]Once in this state, you have about 4 seconds to make contact\n[[YELLOW]]with Mining compatible materials, which will activate Super\n[[YELLOW]]Breaker. Guides.Mining.Section.3=[[DARK_AQUA]]What is Super Breaker?\n[[YELLOW]]Super Breaker is an ability with a cooldown tied to the Mining\n[[YELLOW]]skill. It triples your chance of extra items dropping and\n[[YELLOW]]enables instant break on Mining materials. Guides.Mining.Section.4=[[DARK_AQUA]]How to use Blast Mining:\n[[YELLOW]]With a pickaxe in hand,\n[[YELLOW]]crouch and right-click on TNT from a distance. This will cause the TNT\n[[YELLOW]]to instantly explode. Guides.Mining.Section.5=[[DARK_AQUA]]How does Blast Mining work?\n[[YELLOW]]Blast Mining is an ability with a cooldown tied to the Mining\n[[YELLOW]]skill. It gives bonuses when mining with TNT and allows you\n[[YELLOW]]to remote detonate TNT. There are three parts to Blast Mining.\n[[YELLOW]]The first part is Bigger Bombs, which increases blast radius.\n[[YELLOW]]The second is Demolitions Expert, which decreases damage\n[[YELLOW]]from TNT explosions. The third part simply increases the\n[[YELLOW]]amount of ores dropped from TNT and decreases the\n[[YELLOW]]debris dropped. ##Repair -Guides.Repair.Section.0=[[DARK_AQUA]]About Repair:\n[[YELLOW]]Repair allows you to use an iron block to repair armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Repair tools or armor using the mcMMO Anvil. This is an\n[[YELLOW]]iron block by default and should not be confused with\n[[YELLOW]]the Vanilla Minecraft Anvil. +Guides.Repair.Section.0=[[DARK_AQUA]]\u4fee\u7406\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Repair allows you to use an iron block to repair armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Repair tools or armor using the mcMMO Anvil. This is an\n[[YELLOW]]iron block by default and should not be confused with\n[[YELLOW]]the Vanilla Minecraft Anvil. Guides.Repair.Section.1=[[DARK_AQUA]]How can I use Repair?\n[[YELLOW]]Place down a mcMMO Anvil and right-click to repair the item \n[[YELLOW]]you're currently holding. This consumes 1 item on every use. Guides.Repair.Section.2=[[DARK_AQUA]]How does Repair Mastery work?\n[[YELLOW]]Repair Mastery increases the repair amount. The extra amount\n[[YELLOW]]repaired is influenced by your Repair skill level. Guides.Repair.Section.3=[[DARK_AQUA]]How does Super Repair work?\n[[YELLOW]]Super Repair is a passive ability. When repairing an item,\n[[YELLOW]]it grants players a chance to repair an item with\n[[YELLOW]]double effectiveness. Guides.Repair.Section.4=[[DARK_AQUA]]How does Arcane Forging work?\n[[YELLOW]]This passive ability allows you to repair items with a certain\n[[YELLOW]]chance of maintaining its enchantments. The enchants may be\n[[YELLOW]]kept at their existing levels, downgraded to a lower level,\n[[YELLOW]]or lost entirely. ##Salvage -Guides.Salvage.Section.0=[[DARK_AQUA]]About Salvage:\n[[YELLOW]]Salvage allows you to use an gold block to salvage armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Salvage is a child skill of Repair and Fishing, your Salvage\n[[YELLOW]]skill level is based on your Fishing and Repair skill levels. +Guides.Salvage.Section.0=[[DARK_AQUA]]\u30b5\u30eb\u30d9\u30fc\u30b8\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Salvage allows you to use an gold block to salvage armor and\n[[YELLOW]]tools.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]Salvage is a child skill of Repair and Fishing, your Salvage\n[[YELLOW]]skill level is based on your Fishing and Repair skill levels. Guides.Salvage.Section.1=[[DARK_AQUA]]How can I use Salvage?\n[[YELLOW]]Place down a mcMMO Salvage Anvil and right-click to salvage\n[[YELLOW]]the item you're currently holding. This will break apart the item,\n[[YELLOW]]and give back materials used to craft the item.\n\n[[YELLOW]]For example, salvaging an iron pickaxe will give you iron bars. Guides.Salvage.Section.2=[[DARK_AQUA]]How does Advanced Salvage work?\n[[YELLOW]]When unlocked, this ability allows you to salvage damaged items.\n[[YELLOW]]The yield percentage increases as you level up. A higher yield\n[[YELLOW]]means that you can get more materials back.\n[[YELLOW]]With advanced salvage you will always get 1 material back,\n[[YELLOW]]unless the item is too damaged. So you don't have to worry\n[[YELLOW]]about destroying items without getting anything in return. Guides.Salvage.Section.3=[[DARK_AQUA]]To illustrate how this works, here's an example:\n[[YELLOW]]Let's say we salvage a gold pickaxe which is damaged for 20%,\n[[YELLOW]]this means that the maximum amount you could get is only 2\n[[YELLOW]](because the pick is crafted with 3 ingots - each worth\n[[YELLOW]]33,33% durability) which is equal to 66%. If your yield\n[[YELLOW]]percentage is below 66% you are not able to get 2 ingots.\n[[YELLOW]]If it is above this value you are able to gain the "full amount",\n[[YELLOW]]which means that you will get 2 ingots. @@ -749,13 +754,13 @@ Guides.Salvage.Section.4=[[DARK_AQUA]]How does Arcane Salvage work?\n[[YELLOW]]T ##Smelting Guides.Smelting.Section.0=Coming soon... ##Swords -Guides.Swords.Section.0=[[DARK_AQUA]]About Swords:\n[[YELLOW]]This skill awards combat bonuses to anyone fighting with a\n[[YELLOW]]sword.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained based on the amount of damage dealt to mobs or \n[[YELLOW]]other players when wielding a sword. +Guides.Swords.Section.0=[[DARK_AQUA]]\u5263\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]This skill awards combat bonuses to anyone fighting with a\n[[YELLOW]]sword.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained based on the amount of damage dealt to mobs or \n[[YELLOW]]other players when wielding a sword. Guides.Swords.Section.1=[[DARK_AQUA]]How does Serrated Strikes work?\n[[YELLOW]]Serrated Strikes is an active ability, you can activate it by\n[[YELLOW]]right-clicking with a sword. This ability allows you to deal \n[[YELLOW]]an AoE (Area of Effect) hit. This AoE will do a bonus 25%\n[[YELLOW]]damage and will inflict a bleed effect that lasts for 5 ticks. Guides.Swords.Section.2=[[DARK_AQUA]]How does Counter Attack work?\n[[YELLOW]]Counter Attack is an active ability. When blocking and taking\n[[YELLOW]]hits from mobs, you will have a chance to reflect 50% of \n[[YELLOW]]the damage that was taken. Guides.Swords.Section.3=[[DARK_AQUA]]How does Rupture work?\n[[YELLOW]]Rupture causes enemies to take damage every two seconds. The \n[[YELLOW]]target will bleed until the effect wears off, or death, \n[[YELLOW]]whichever comes first.\n[[YELLOW]]The duration of the bleed is increased by your sword skill. ##Taming -Guides.Taming.Section.0=[[DARK_AQUA]]About Taming:\n[[YELLOW]]Taming will give players various combat bonuses when using\n[[YELLOW]]tamed wolves.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you need to tame wolves/ocelots or\n[[YELLOW]]get into combat with your wolves. -Guides.Taming.Section.1=[[DARK_AQUA]]How does Call of the Wild work?\n[[YELLOW]]Call of the Wild is an active ability that will allow you to summon\n[[YELLOW]]a wolf or an ocelot by your side. You can do this by\n[[YELLOW]]left-clicking while holding bones or fish. +Guides.Taming.Section.0=[[DARK_AQUA]]\u8abf\u6559\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Taming will give players various combat bonuses when using\n[[YELLOW]]tamed wolves.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]To gain XP in this skill, you need to tame wolves/ocelots or\n[[YELLOW]]get into combat with your wolves. +Guides.Taming.Section.1=[DARK_AQUA]]How does Call of the Wild work?\n[[YELLOW]]Call of the Wild is an active ability that will allow you to summon\n[[YELLOW]]a wolf or an ocelot by your side. You can do this by\n[[YELLOW]]sneaking + left-clicking while holding bones or fish. Guides.Taming.Section.2=[[DARK_AQUA]]How does Beast Lore work?\n[[YELLOW]]Beast Lore allows players to inspect pets and to check the\n[[YELLOW]]stats of wolves and ocelots. Left-click a wolf or ocelot to use\n[[YELLOW]]Beast Lore. Guides.Taming.Section.3=[[DARK_AQUA]]How does Gore work?\n[[YELLOW]]Gore is a passive ability that has a chance of inflicting a\n[[YELLOW]]bleeding effect on your wolves' targets. Guides.Taming.Section.4=[[DARK_AQUA]]How does Sharpened Claws work?\n[[YELLOW]]Sharpened Claws provides a damage bonus to damage dealt\n[[YELLOW]]by wolves. The damage bonus depends on your Taming level. @@ -764,14 +769,14 @@ Guides.Taming.Section.6=[[DARK_AQUA]]How does Thick Fur work?\n[[YELLOW]]This pa Guides.Taming.Section.7=[[DARK_AQUA]]How does Shock Proof work?\n[[YELLOW]]This passive ability reduces damage done to wolves\n[[YELLOW]]from explosions. Guides.Taming.Section.8=[[DARK_AQUA]]How does Fast Food Service work?\n[[YELLOW]]This passive ability gives wolves a chance to heal whenever\n[[YELLOW]]they perform an attack. ##Unarmed -Guides.Unarmed.Section.0=[[DARK_AQUA]]About Unarmed:\n[[YELLOW]]Unarmed will give players various combat bonuses when using\n[[YELLOW]]your fists as a weapon. \n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained based on the amount of damage dealt to mobs \n[[YELLOW]]or other players when unarmed. +Guides.Unarmed.Section.0=[[DARK_AQUA]]\u7d20\u624b\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Unarmed will give players various combat bonuses when using\n[[YELLOW]]your fists as a weapon. \n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained based on the amount of damage dealt to mobs \n[[YELLOW]]or other players when unarmed. Guides.Unarmed.Section.1=[[DARK_AQUA]]How does Berserk work?\n[[YELLOW]]Beserk is an active ability that is activated by\n[[YELLOW]]right-clicking. While in Beserk mode, you deal 50% more\n[[YELLOW]]damage and you can break weak materials instantly, such as\n[[YELLOW]]Dirt and Grass. Guides.Unarmed.Section.2=[[DARK_AQUA]]How does Iron Arm work?\n[[YELLOW]]Iron Arm increases the damage dealt when hitting mobs or\n[[YELLOW]]players with your fists. Guides.Unarmed.Section.3=[[DARK_AQUA]]How does Arrow Deflect work?\n[[YELLOW]]Arrow Deflect is a passive ability that gives you a chance\n[[YELLOW]]to deflect arrows shot by Skeletons or other players.\n[[YELLOW]]The arrow will fall harmlessly to the ground. Guides.Unarmed.Section.4=[[DARK_AQUA]]How does Iron Grip work?\n[[YELLOW]]Iron Grip is a passive ability that counters disarm. As your\n[[YELLOW]]unarmed level increases, the chance of preventing a disarm increases. Guides.Unarmed.Section.5=[[DARK_AQUA]]How does Disarm work?\n[[YELLOW]]This passive ability allows players to disarm other players,\n[[YELLOW]]causing the target's equipped item to fall to the ground. ##Woodcutting -Guides.Woodcutting.Section.0=[[DARK_AQUA]]About Woodcutting:\n[[YELLOW]]Woodcutting is all about chopping down trees.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained whenever you break log blocks. +Guides.Woodcutting.Section.0=[[DARK_AQUA]]\u6728\u3053\u308a\u306b\u3064\u3044\u3066\uff1a\n[[YELLOW]]Woodcutting is all about chopping down trees.\n\n[[DARK_AQUA]]XP GAIN:\n[[YELLOW]]XP is gained whenever you break log blocks. Guides.Woodcutting.Section.1=[[DARK_AQUA]]How does Tree Feller work?\n[[YELLOW]]Tree Feller is an active ability, you can right-click\n[[YELLOW]]while holding an ax to activate Tree Feller. This will\n[[YELLOW]]cause the entire tree to break instantly, dropping all\n[[YELLOW]]of its logs at once. Guides.Woodcutting.Section.2=[[DARK_AQUA]]How does Leaf Blower work?\n[[YELLOW]]Leaf Blower is a passive ability that will cause leaf\n[[YELLOW]]blocks to break instantly when hit with an axe. By default,\n[[YELLOW]]this ability unlocks at level 100. Guides.Woodcutting.Section.3=[[DARK_AQUA]]How do Double Drops work?\n[[YELLOW]]This passive ability gives you a chance to obtain an extra\n[[YELLOW]]block for every log you chop. @@ -832,8 +837,8 @@ MOTD.Website=[[GOLD]][mcMMO] [[GREEN]]{0}[[YELLOW]] - mcMMO \u30a6\u30a7\u30d6\u Smelting.SubSkill.UnderstandingTheArt.Name=\u82b8\u8853\u3092\u7406\u89e3\u3059\u308b Smelting.SubSkill.UnderstandingTheArt.Description=\u6d1e\u7a9f\u306e\u4e2d\u3067\u88fd\u932c\u306b\u6642\u9593\u3092\u304b\u3051\u904e\u304e\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002\n\u88fd\u932c\u306e\u3055\u307e\u3056\u307e\u306a\u7279\u6027\u3092\u5f37\u5316\u3057\u307e\u3059\u3002 Smelting.SubSkill.UnderstandingTheArt.Stat=\u30d0\u30cb\u30e9XP Multiplier: [[YELLOW]]{0}x -Smelting.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (\u30d0\u30cb\u30e9XP\u30d6\u30fc\u30b9\u30c8) -Smelting.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (\u30d5\u30e9\u30c3\u30af\u30b9\u30de\u30a4\u30cb\u30f3\u30b0) +Smelting.Ability.Locked.0=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30d0\u30cb\u30e9XP\u30d6\u30fc\u30b9\u30c8) +Smelting.Ability.Locked.1=\u30ed\u30c3\u30af\u3055\u308c\u308b\u307e\u3067 {0}+ \u30b9\u30ad\u30eb (\u30d5\u30e9\u30c3\u30af\u30b9\u30de\u30a4\u30cb\u30f3\u30b0) Smelting.SubSkill.FuelEfficiency.Name=\u71c3\u6599\u52b9\u7387 Smelting.SubSkill.FuelEfficiency.Description=\u88fd\u932c\u6642\u306b\u7ac8\u3067\u4f7f\u7528\u3059\u308b\u71c3\u6599\u306e\u71c3\u713c\u6642\u9593\u3092\u9577\u304f\u3059\u308b\u3002 Smelting.SubSkill.FuelEfficiency.Stat=\u71c3\u6599\u52b9\u7387 \u4e57\u6570: [[YELLOW]]{0}x From 43819605fa9e360e004ae501447c8485711186d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Marczink=C3=B3?= Date: Tue, 2 Jul 2019 23:44:23 +0200 Subject: [PATCH 11/31] Update locale_hu_HU.properties --- .../resources/locale/locale_hu_HU.properties | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/resources/locale/locale_hu_HU.properties b/src/main/resources/locale/locale_hu_HU.properties index 83ba3228d..3d734b7e6 100644 --- a/src/main/resources/locale/locale_hu_HU.properties +++ b/src/main/resources/locale/locale_hu_HU.properties @@ -32,7 +32,7 @@ JSON.Unarmed=Pusztakezek JSON.Woodcutting=Fav\u00E1g\u00E1s JSON.URL.Website=A hivatalos mcMMO weboldal! JSON.URL.Discord=A hivatalos mcMMO Discord szerver! -JSON.URL.Patreon=T\u00E1mogat\u00E1s nossr50-nak a munk\u00E1j\u00E1r\u00E1\u00E9rt \u00E9s az mcMMO-nak a Patreonon! +JSON.URL.Patreon=T\u00E1mogat\u00E1s nossr50-nak a munk\u00E1j\u00E1\u00E9rt \u00E9s az mcMMO-nak a Patreon-on! JSON.URL.Spigot=A hivatalos mcMMO Spigot Forr\u00E1s Oldal! JSON.URL.Translation=Ford\u00EDtsd le az mcMMO-t m\u00E1s nyelvekre! JSON.URL.Wiki=A hivatalos mcMMO wiki! @@ -216,8 +216,10 @@ Excavation.Ability.Ready=[[GOLD]]El\u0151k\u00E9sz\u00EDted[[DARK_AQUA]] az \u00 Excavation.SubSkill.GigaDrillBreaker.Name=Giga F\u00FAr\u00F3-T\u00F6r\u0151 Excavation.SubSkill.GigaDrillBreaker.Description=3x T\u00E1rgy Es\u00E9si Es\u00E9ly, 3x XP, +Sebess\u00E9g Excavation.SubSkill.GigaDrillBreaker.Stat=Giga F\u00FAr\u00F3-T\u00F6r\u0151 Id\u0151tartam -Excavation.SubSkill.TreasureHunter.Name=R\u00E9g\u00E9szet -Excavation.SubSkill.TreasureHunter.Description=Fedezd fel a f\u00F6ld titkait! +Excavation.SubSkill.Archaeology.Name=R\u00E9g\u00E9szet +Excavation.SubSkill.Archaeology.Description=Fedezd fel a f\u00F6ld titkait! A magas k\u00E9pess\u00E9g szint n\u00F6veli az es\u00E9ly\u00E9t, hogy tapasztalatpontot tal\u00E1lj, amikor kincset tal\u00E1lsz! +Excavation.SubSkill.Archaeology.Stat=R\u00E9g\u00E9szet Tapasztalatpont Es\u00E9ly +Excavation.SubSkill.Archaeology.Stat.Extra=R\u00E9g\u00E9szet Tapasztalatpont Mennyis\u00E9g Excavation.Listener=\u00C1s\u00E1s: Excavation.SkillName=\u00C1S\u00C1S Excavation.Skills.GigaDrillBreaker.Off=*Giga F\u00FAr\u00F3-T\u00F6r\u0151 v\u00E9get \u00E9rt** @@ -249,7 +251,7 @@ Fishing.SubSkill.FishermansDiet.Description=N\u00F6veli a kihal\u00E1szott \u00E Fishing.SubSkill.FishermansDiet.Stat=Horg\u00E1szok Di\u00E9t\u00E1ja:[[GREEN]] Szint {0} Fishing.SubSkill.MasterAngler.Name=Mester Horg\u00E1sz Fishing.SubSkill.MasterAngler.Description=N\u00F6veli a Kap\u00E1s es\u00E9ly\u00E9t horg\u00E1szat k\u00F6zben -Fishing.SubSkill.MasterAngler.Stat=Hozz\u00E1adott Nagyobb Harap\u00E1si es\u00E9ly a jelenlegi helyen: [[GREEN]]+[[YELLOW]]{0} +Fishing.SubSkill.MasterAngler.Stat=Hozz\u00E1adott Nagyobb Harap\u00E1si es\u00E9ly a jelenlegi helyen: [[GREEN]]+{0} Fishing.SubSkill.IceFishing.Name=J\u00E9g Horg\u00E1szat Fishing.SubSkill.IceFishing.Description=Lehet\u0151v\u00E9 teszi sz\u00E1modra, hogy fagyos t\u00E1jakon is horg\u00E1szhass Fishing.SubSkill.IceFishing.Stat=J\u00E9g Horg\u00E1szat @@ -393,8 +395,8 @@ Salvage.Skills.ArcaneSuccess=[[GREEN]]Sikeresen kinyert\u00E9l minden tud\u00E1s Salvage.Listener.Anvil=[[DARK_RED]]Lehelyezt\u00E9l egy \u00C9rt\u00E9kment\u0151 \u00DCll\u0151t. Haszn\u00E1ld ezt eszk\u00F6z\u00F6k, \u00E9s p\u00E1nc\u00E9lzatok \u00FAjrahasznos\u00EDt\u00E1shoz. Salvage.Listener=\u00DAjrahasznos\u00EDt\u00E1s: Salvage.SkillName=\u00DAJRAHASZNOS\u00CDT\u00C1S -Salvage.Skills.Lottery.Normal=[[GOLD]]\u00DAjrahasznos\u00EDthatsz [[GREEN]]{0}[[GOLD]] anyagot ebb\u0151l [[DARK_AQUA]]{1}[[GOLD]]. -Salvage.Skills.Lottery.Perfect=[[GREEN]][[BOLD]]T\u00F6k\u00E9letes![[RESET]][[GOLD]] K\u00F6nnyed\u00E9n \u00FAjrahasznos\u00EDtott\u00E1l egy [[GREEN]]{1}[[GOLD]]-t visszanyerve [[DARK_AQUA]]{0}[[GOLD]] anyagot. +Salvage.Skills.Lottery.Normal=[[GOLD]]\u00DAjrahasznos\u00EDthatsz [[DARK_AQUA]]{0}[[GOLD]] anyagot ebb\u0151l [[YELLOW]]{1}[[GOLD]]. +Salvage.Skills.Lottery.Perfect=[[GREEN]][[BOLD]]T\u00F6k\u00E9letes![[RESET]][[GOLD]] K\u00F6nnyed\u00E9n \u00FAjrahasznos\u00EDtott\u00E1l egy [[DARK_AQUA]]{1}[[GOLD]]-t visszanyerve [[DARK_AQUA]]{0}[[GOLD]] anyagot. Salvage.Skills.Lottery.Untrained=[[GRAY]]M\u00E9g nem vagy el\u00E9g k\u00E9pezett az \u00FAjrahasznos\u00EDt\u00E1sban. Csak [[RED]]{0}[[GRAY]] anyagot tudt\u00E1l helyre\u00E1ll\u00EDtani ebb\u0151l [[GREEN]]{1}[[GRAY]]. #Anvil (Shared between SALVAGE and REPAIR) Anvil.Unbreakable=Ez a t\u00E1rgy t\u00F6rhetetlen! @@ -478,13 +480,13 @@ Taming.SubSkill.Pummel.TargetMessage=H\u00E1tra lett\u00E9l l\u00F6kve egy farka Taming.Listener.Wolf=[[DARK_GRAY]]A Farkasod hozz\u00E1d oson... Taming.Listener=Szel\u00EDd\u00EDt\u00E9s: Taming.SkillName=SZELID\u00CDT\u00C9S -Taming.Summon.Complete=[[GREEN]]Sikeres Megid\u00E9z\u00E9s -Taming.Summon.Lifespan= (\u00C9lettartam: {0}mp) -Taming.Summon.Fail.Ocelot=[[RED]]T\u00FAl sok ocelot van a k\u00F6zeledben, hogy t\u00F6bbet id\u00E9zhess. -Taming.Summon.Fail.Wolf=[[RED]]T\u00FAl sok farkas van a k\u00F6zeledben, hogy t\u00F6bbet id\u00E9zhess. -Taming.Summon.Fail.Horse=[[RED]]T\u00FAl sok l\u00F3 van a k\u00F6zeledben, hogy t\u00F6bbet id\u00E9zhess. -Taming.Summon.Fail.TooMany=[[RED]]El\u00E9rted a maxim\u00E1lis \u00E1llat-id\u00E9z\u00E9si limited. [[YELLOW]]({0}) -Taming.Summon.Name.Format={0} \u00E1llata: {1} +Taming.Summon.COTW.Success.WithoutLifespan=[[GREEN]](A Vadon Szava) [[GRAY]]Megid\u00E9zt\u00E9l egy [[GOLD]]{0}[[GRAY]] +Taming.Summon.COTW.Success.WithLifespan=[[GREEN]](A Vadon Szava) [[GRAY]]Megid\u00E9zt\u00E9l egy [[GOLD]]{0}[[GRAY]] \u00E9s az id\u0151tartama [[GOLD]]{1}[[GRAY]] m\u00E1sodperc. +Taming.Summon.COTW.Limit=[[GREEN]](A Vadon Szava) [[GRAY]]Egyszerre csak [[RED]]{0} [[GRAY]]megid\u00E9zett [[GRAY]]{1} h\u00E1zi\u00E1llat lehet egyid\u0151ben. +Taming.Summon.COTW.TimeExpired=[[GREEN]](A Vadon Szava) [[GRAY]]Az id\u0151 v\u00E9get \u00E9r, [[GOLD]]{0}[[GRAY]] elt\u00E1vozik. +Taming.Summon.COTW.BreedingDisallowed=[[GREEN]](A Vadon Szava) [[RED]]Nem szapor\u00EDthatsz megid\u00E9zett \u00E1llatot. +Taming.Summon.COTW.NeedMoreItems=[[GREEN]](A Vadon Szava) [[GRAY]]Sz\u00FCks\u00E9g van [[YELLOW]]{0}[[GRAY]] t\u00F6bb [[DARK_AQUA]]{1}[[GRAY]](m) +Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0} \u00E1llata {1} #UNARMED Unarmed.Ability.Bonus.0=Vas-\u00D6k\u00F6l St\u00EDlus Unarmed.Ability.Bonus.1=+{0} Sebz\u00E9s Fejleszt\u00E9s @@ -635,7 +637,7 @@ Commands.Party.MembersNear=[[DARK_GRAY]]A K\u00D6ZELEDBEN [[DARK_AQUA]]{0}[[DARK Commands.Party.Accept=[[GREEN]]- Party felk\u00E9r\u00E9s elfogad\u00E1sa Commands.Party.Chat.Off=Csak party Chat [[RED]]kikapcsolva Commands.Party.Chat.On=Csak party Chat [[GREEN]]bekapcsolva -Commands.Party.Commands=---[][[GREEN]]PARTY PARANCSOK[[RED]][]--- +Commands.Party.Commands=[[RED]]---[][[GREEN]]PARTY PARANCSOK[[RED]][]--- Commands.Party.Invite.0=[[RED]]FIGYELEM: [[GREEN]]Party felk\u00E9r\u00E9st kapt\u00E1l a(z) {0}-ba/be {1}-t\u00F3l/t\u0151l. Commands.Party.Invite.1=[[YELLOW]]\u00CDrd be, hogy [[GREEN]]/party accept[[YELLOW]] a megh\u00EDv\u00E1s elfogad\u00E1s\u00E1hoz. Commands.Party.Invite=[[GREEN]]- Party megh\u00EDv\u00E1s k\u00FCld\u00E9se. @@ -927,7 +929,7 @@ Guides.Swords.Section.2=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik az Ellent\u00E1mad Guides.Swords.Section.3=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik a T\u00F6r\u00E9s?\n[[YELLOW]]A T\u00F6r\u00E9s k\u00E9t m\u00E1sodpercenk\u00E9nt sebzi az ellens\u00E9geidet. A c\u00E9lpont \n[[YELLOW]]mindaddig v\u00E9rezni fog, m\u00EDg a V\u00E9rz\u00E9s id\u0151tartam le nem j\u00E1r, vagy az \u00E1ldozat meg nem hal. \n[[YELLOW]]A V\u00E9rz\u00E9s id\u0151tartam a Kardok szintedt\u0151l f\u00FCgg. ##Taming Guides.Taming.Section.0=[[DARK_AQUA]]A szelid\u00EDt\u00E9sr\u0151l:\n[[YELLOW]]A Szel\u00EDd\u00EDt\u00E9s k\u00FCl\u00F6nb\u00F6z\u0151 harci b\u00F3nuszokkal l\u00E1tja el a j\u00E1t\u00E9kost, ha \n[[YELLOW]]szel\u00EDd\u00EDtett farkasokkal van.\n\n[[DARK_AQUA]]TAPASZTALAT SZERZ\u00C9S:\n[[YELLOW]]Szel\u00EDd\u00EDts farkasokat/ocelotokat, vagy harcolj \n[[YELLOW]]a farkasaid oldal\u00E1n. -Guides.Taming.Section.1=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik a Vadon H\u00EDv\u00E1sa?\n[[YELLOW]]A Vadon H\u00EDv\u00E1sa egy aktiv\u00E1lhat\u00F3 k\u00E9pess\u00E9g, amellyel magad mell\u00E9 id\u00E9zhetsz \n[[YELLOW]]egy farkast vagy egy ocelotot. Ezt \n[[YELLOW]]csonttal vagy hallal val\u00F3 balkattint\u00E1ssal teheted meg. +Guides.Taming.Section.1=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik a Vadon H\u00EDv\u00E1sa?\n[[YELLOW]]A Vadon H\u00EDv\u00E1sa egy aktiv\u00E1lhat\u00F3 k\u00E9pess\u00E9g, amellyel magad mell\u00E9 id\u00E9zhetsz \n[[YELLOW]]egy farkast vagy egy ocelotot. Ezt \n[[YELLOW]]csonttal vagy hallal val\u00F3 guggol\u00E1s k\u00F6zben balkattint\u00E1ssal teheted meg. Guides.Taming.Section.2=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik a Vad\u00E1llat-tan?\n[[YELLOW]]A Vad\u00E1llat-tan lehet\u0151v\u00E9 teszi a \n[[YELLOW]]farkasok \u00E9s ocelotok statisztik\u00E1inak megvizsg\u00E1l\u00E1s\u00E1t. Haszn\u00E1lat\u00E1hoz bal klikkelj egy farkasra\n[[YELLOW]]vagy ocelotra. Guides.Taming.Section.3=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dik a Led\u00F6f\u00E9s?\n[[YELLOW]]A led\u00F6f\u00E9s egy passz\u00EDv k\u00E9pess\u00E9g, amely lehet\u0151v\u00E9 teszi, \n[[YELLOW]]hogy a farkasok c\u00E9lpontja V\u00E9rz\u00E9st kapjon. Guides.Taming.Section.4=[[DARK_AQUA]]Hogyan m\u0171k\u00F6dnek az \u00C9les Karmok?\n[[YELLOW]]Az \u00C9les Karmok b\u00F3nusz sebz\u00E9st ad a farkasok t\u00E1mad\u00E1sainak. \n[[YELLOW]]Ez a b\u00F3nusz a Szel\u00EDd\u00EDt\u00E9s szintedt\u0151l f\u00FCgg. @@ -1087,7 +1089,7 @@ Scoreboard.Misc.Ability=K\u00E9pess\u00E9g #DATABASE RECOVERY Profile.PendingLoad=[[RED]]Az mcMMO j\u00E1t\u00E9kos adatod m\u00E9g nincs bet\u00F6ltve. Profile.Loading.Success=[[GREEN]]mcMMO profil sikeresen bet\u00F6ltve. -Profile.Loading.FailurePlayer=[[RED]]Az mcMMO-nak probl\u00E9m\u00E1i vannak az adataid bet\u00F6lt\u00E9sekor, megpr\u00F3b\u00E1ltuk bet\u00F6lteni [[GREEN]]{0}[[RED]]x.[[LIGHT_GRAY]] Ezzel kapcsolatban \u00E9rdemes kapcsolatba l\u00E9pni a szerver adminisztr\u00E1torokkal. Az mcMMO megpr\u00F3b\u00E1lja bet\u00F6lteni az adatait mindaddig, am\u00EDg nem kapcsol\u00F3dsz le. Nem kapsz XP-t, \u00E9s nem tudod haszn\u00E1lni a k\u00E9pess\u00E9geket, am\u00EDg az adataid nem t\u00F6lt\u0151dnek be. +Profile.Loading.FailurePlayer=[[RED]]Az mcMMO-nak probl\u00E9m\u00E1i vannak az adataid bet\u00F6lt\u00E9sekor, megpr\u00F3b\u00E1ltuk bet\u00F6lteni [[GREEN]]{0}[[RED]]x.[[RED]] Ezzel kapcsolatban \u00E9rdemes kapcsolatba l\u00E9pni a szerver adminisztr\u00E1torokkal. Az mcMMO megpr\u00F3b\u00E1lja bet\u00F6lteni az adatait mindaddig, am\u00EDg nem kapcsol\u00F3dsz le. Nem kapsz XP-t, \u00E9s nem tudod haszn\u00E1lni a k\u00E9pess\u00E9geket, am\u00EDg az adataid nem t\u00F6lt\u0151dnek be. Profile.Loading.FailureNotice=[[DARK_RED]][A][[RED]] az mcMMO nem tudta bet\u00F6lteni ennek a j\u00E1t\u00E9kosnak az adatait [[YELLOW]]{0}[[RED]]. [[LIGHT_PURPLE]]K\u00E9rj\u00FCk, ellen\u0151rizd az adatb\u00E1zis be\u00E1ll\u00EDt\u00E1sait. Eddig tett k\u00EDs\u00E9rletek {1}. #Holiday Holiday.AprilFools.Levelup=[[GOLD]]{0} jelenlegi szint [[GREEN]]{1}[[GOLD]]! @@ -1096,3 +1098,6 @@ Holiday.Anniversary=[[BLUE]]Boldog {0}. \u00C9vfordul\u00F3t!\n[[BLUE]]nossr50, Reminder.Squelched=[[GRAY]]Eml\u00E9keztet\u0151: jelenleg nem kapsz \u00E9rtes\u00EDt\u00E9seket az mcMMO-t\u00F3l. Ahhoz, hogy enged\u00E9lyezd az \u00E9rtes\u00EDt\u00E9seket, futtasd \u00FAjra a /mcnotify parancsot. Ez egy automatikus, \u00F3r\u00E1nk\u00E9nti eml\u00E9keztet\u0151. #Locale Locale.Reloaded=[[GREEN]]Ford\u00EDt\u00E1s \u00FAjrat\u00F6ltve! +#Player Leveling Stuff +LevelCap.PowerLevel=[[GOLD]]([[GREEN]]mcMMO[[GOLD]]) [[YELLOW]]El\u00E9rted ezt a teljes\u00EDtm\u00E9nyszintet [[RED]]{0}[[YELLOW]]. Ezen a ponton megsz\u0171nik a k\u00E9pess\u00E9gek szintje. +LevelCap.Skill=[[GOLD]]([[GREEN]]mcMMO[[GOLD]]) [[YELLOW]]El\u00E9rted ezt a szintet [[RED]]{0}[[YELLOW]] ebben [[GOLD]]{1}[[YELLOW]]. Ezen a ponton megsz\u0171nik a k\u00E9pess\u00E9g szintje. From 0af3c82612142b261df686ee13cbcb0fb8194aee Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 14:46:55 -0700 Subject: [PATCH 12/31] Fixed a bug that could prevent a Tree from being removed by Tree Feller if 2 or more players were using Tree Feller simultaneously --- Changelog.txt | 3 + pom.xml | 2 +- .../skills/woodcutting/Woodcutting.java | 247 ++---------------- .../woodcutting/WoodcuttingManager.java | 230 +++++++++++++++- 4 files changed, 248 insertions(+), 234 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0da17bf62..58a362229 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.94 + Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big + Version 2.1.93 Fixed a bug where players would be told they could not breed summoned animals when the animals weren't summoned (bug didn't actually do anything besides send you a message) diff --git a/pom.xml b/pom.xml index d9949935f..6c0c5e07d 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.93 + 2.1.94-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO 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 9b08beab7..6f98b08cc 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java @@ -1,220 +1,27 @@ -package com.gmail.nossr50.skills.woodcutting; - -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.BlockUtils; -import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.skills.SkillUtils; -import org.bukkit.Material; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.inventory.ItemStack; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -public final class Woodcutting { - public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); - protected static boolean treeFellerReachedThreshold = false; - - private Woodcutting() {} - - /** - * Retrieves the experience reward from a log - * - * @param blockState Log being broken - * @return Amount of experience - */ - protected static int getExperienceFromLog(BlockState blockState) { - if (mcMMO.getModManager().isCustomLog(blockState)) { - return mcMMO.getModManager().getBlock(blockState).getXpGain(); - } - - return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); - } - - /** - * Retrieves the experience reward from logging via Tree Feller - * Experience is reduced per log processed so far - * Experience is only reduced if the config option to reduce Tree Feller XP is set - * Experience per log will not fall below 1 unless the experience for that log is set to 0 in the config - * - * @param blockState Log being broken - * @param woodCount how many logs have given out XP for this tree feller so far - * @return Amount of experience - */ - protected static int processTreeFellerXPGains(BlockState blockState, int woodCount) { - int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); - - if(rawXP <= 0) - return 0; - - if(ExperienceConfig.getInstance().isTreeFellerXPReduced()) { - int reducedXP = 1 + (woodCount * 5); - rawXP = Math.max(1, rawXP - reducedXP); - return rawXP; - } else { - return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); - } - } - - - - /** - * Checks for double drops - * - * @param blockState Block being broken - */ - protected static void checkForDoubleDrop(BlockState blockState) { - if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) { - Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); - } - else { - if (Config.getInstance().getWoodcuttingDoubleDropsEnabled(blockState.getBlockData())) { - Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); - } - } - } - - /** - * The x/y differences to the blocks in a flat cylinder around the center - * block, which is excluded. - */ - private static final int[][] directions = { - new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1}, - new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2}, - new int[] { 0, -2}, new int[] { 0, -1}, new int[] { 0, 1}, new int[] { 0, 2}, - new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2}, - new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1}, - }; - - /** - * Processes Tree Feller in a recursive manner - * - * @param blockState Block being checked - * @param treeFellerBlocks List of blocks to be removed - */ - /* - * Algorithm: An int[][] of X/Z directions is created on static class - * initialization, representing a cylinder with radius of about 2 - the - * (0,0) center and all (+-2, +-2) corners are omitted. - * - * handleBlock() returns a boolean, which is used for the sole purpose of - * switching between these two behaviors: - * - * (Call blockState "this log" for the below explanation.) - * - * [A] There is another log above this log (TRUNK) - * Only the flat cylinder in the directions array is searched. - * [B] There is not another log above this log (BRANCH AND TOP) - * The cylinder in the directions array is extended up and down by 1 - * block in the Y-axis, and the block below this log is checked as - * well. Due to the fact that the directions array will catch all - * blocks on a red mushroom, the special method for it is eliminated. - * - * This algorithm has been shown to achieve a performance of 2-5 - * milliseconds on regular trees and 10-15 milliseconds on jungle trees - * once the JIT has optimized the function (use the ability about 4 times - * before taking measurements). - */ - protected static void processTree(BlockState blockState, Set treeFellerBlocks) { - List futureCenterBlocks = new ArrayList(); - - // Check the block up and take different behavior (smaller search) if it's a log - if (handleBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) { - for (int[] dir : directions) { - handleBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); - - if (treeFellerReachedThreshold) { - return; - } - } - } - else { - // Cover DOWN - handleBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks); - // Search in a cube - for (int y = -1; y <= 1; y++) { - for (int[] dir : directions) { - handleBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); - - if (treeFellerReachedThreshold) { - return; - } - } - } - } - - // Recursive call for each log found - for (BlockState futureCenterBlock : futureCenterBlocks) { - if (treeFellerReachedThreshold) { - return; - } - - processTree(futureCenterBlock, treeFellerBlocks); - } - } - - /** - * Handles the durability loss - * - * @param treeFellerBlocks List of blocks to be removed - * @param inHand tool being used - * @return True if the tool can sustain the durability loss - */ - protected static boolean handleDurabilityLoss(Set treeFellerBlocks, ItemStack inHand) { - //Treat the NBT tag for unbreakable and the durability enchant differently - if(inHand.getItemMeta() != null && inHand.getItemMeta().isUnbreakable()) { - return true; - } - - short durabilityLoss = 0; - Material type = inHand.getType(); - - for (BlockState blockState : treeFellerBlocks) { - if (BlockUtils.isLog(blockState)) { - durabilityLoss += Config.getInstance().getAbilityToolDamage(); - } - } - - SkillUtils.handleDurabilityChange(inHand, durabilityLoss); - return (inHand.getDurability() < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability())); - } - - /** - * Handle a block addition to the list of blocks to be removed and to the - * list of blocks used for future recursive calls of - * 'processTree()' - * - * @param blockState Block to be added - * @param futureCenterBlocks List of blocks that will be used to call - * 'processTree()' - * @param treeFellerBlocks List of blocks to be removed - * @return true if and only if the given blockState was a Log not already - * in treeFellerBlocks. - */ - private static boolean handleBlock(BlockState blockState, List futureCenterBlocks, Set treeFellerBlocks) { - if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) { - return false; - } - - // Without this check Tree Feller propagates through leaves until the threshold is hit - if (treeFellerBlocks.size() > treeFellerThreshold) { - treeFellerReachedThreshold = true; - } - - if (BlockUtils.isLog(blockState)) { - treeFellerBlocks.add(blockState); - futureCenterBlocks.add(blockState); - return true; - } - else if (BlockUtils.isLeaves(blockState)) { - treeFellerBlocks.add(blockState); - return false; - } - return false; - } -} +//package com.gmail.nossr50.skills.woodcutting; +// +//import com.gmail.nossr50.config.Config; +//import com.gmail.nossr50.config.experience.ExperienceConfig; +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.mcMMO; +//import com.gmail.nossr50.util.BlockUtils; +//import com.gmail.nossr50.util.Misc; +//import com.gmail.nossr50.util.skills.SkillUtils; +//import org.bukkit.Material; +//import org.bukkit.block.BlockFace; +//import org.bukkit.block.BlockState; +//import org.bukkit.inventory.ItemStack; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Set; +// +//public final class Woodcutting { +// public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); +// +// private Woodcutting() {} +// +// +// +// +//} diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 81b4a0b86..f2cc6256b 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,5 +1,7 @@ package com.gmail.nossr50.skills.woodcutting; +import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -14,19 +16,39 @@ import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; public class WoodcuttingManager extends SkillManager { + private boolean treeFellerReachedThreshold = false; + private static int treeFellerThreshold; //TODO: Shared setting, will be removed in 2.2 + + /** + * The x/y differences to the blocks in a flat cylinder around the center + * block, which is excluded. + */ + private static final int[][] directions = { + new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1}, + new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2}, + new int[] { 0, -2}, new int[] { 0, -1}, new int[] { 0, 1}, new int[] { 0, 2}, + new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2}, + new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1}, + }; + public WoodcuttingManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.WOODCUTTING); + treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); } public boolean canUseLeafBlower(ItemStack heldItem) { @@ -52,7 +74,7 @@ public class WoodcuttingManager extends SkillManager { * @param blockState Block being broken */ public void woodcuttingBlockCheck(BlockState blockState) { - int xp = Woodcutting.getExperienceFromLog(blockState); + int xp = getExperienceFromLog(blockState); switch (blockState.getType()) { case BROWN_MUSHROOM_BLOCK: @@ -61,7 +83,7 @@ public class WoodcuttingManager extends SkillManager { default: if (canGetDoubleDrops()) { - Woodcutting.checkForDoubleDrop(blockState); + checkForDoubleDrop(blockState); } } @@ -77,20 +99,20 @@ public class WoodcuttingManager extends SkillManager { Player player = getPlayer(); Set treeFellerBlocks = new HashSet(); - Woodcutting.treeFellerReachedThreshold = false; + treeFellerReachedThreshold = false; - Woodcutting.processTree(blockState, treeFellerBlocks); + processTree(blockState, treeFellerBlocks); // If the player is trying to break too many blocks - if (Woodcutting.treeFellerReachedThreshold) { - Woodcutting.treeFellerReachedThreshold = false; + if (treeFellerReachedThreshold) { + treeFellerReachedThreshold = false; NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Threshold"); return; } // If the tool can't sustain the durability loss - if (!Woodcutting.handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand())) { + if (!handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand())) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Splinter"); double health = player.getHealth(); @@ -102,8 +124,135 @@ public class WoodcuttingManager extends SkillManager { return; } - dropBlocks(treeFellerBlocks); - Woodcutting.treeFellerReachedThreshold = false; // Reset the value after we're done with Tree Feller each time. + dropTreeFellerLootFromBlocks(treeFellerBlocks); + treeFellerReachedThreshold = false; // Reset the value after we're done with Tree Feller each time. + } + + /** + * Processes Tree Feller in a recursive manner + * + * @param blockState Block being checked + * @param treeFellerBlocks List of blocks to be removed + */ + /* + * Algorithm: An int[][] of X/Z directions is created on static class + * initialization, representing a cylinder with radius of about 2 - the + * (0,0) center and all (+-2, +-2) corners are omitted. + * + * processTreeFellerTargetBlock() returns a boolean, which is used for the sole purpose of + * switching between these two behaviors: + * + * (Call blockState "this log" for the below explanation.) + * + * [A] There is another log above this log (TRUNK) + * Only the flat cylinder in the directions array is searched. + * [B] There is not another log above this log (BRANCH AND TOP) + * The cylinder in the directions array is extended up and down by 1 + * block in the Y-axis, and the block below this log is checked as + * well. Due to the fact that the directions array will catch all + * blocks on a red mushroom, the special method for it is eliminated. + * + * This algorithm has been shown to achieve a performance of 2-5 + * milliseconds on regular trees and 10-15 milliseconds on jungle trees + * once the JIT has optimized the function (use the ability about 4 times + * before taking measurements). + */ + private void processTree(BlockState blockState, Set treeFellerBlocks) { + List futureCenterBlocks = new ArrayList(); + + // Check the block up and take different behavior (smaller search) if it's a log + if (processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) { + for (int[] dir : directions) { + processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); + + if (treeFellerReachedThreshold) { + return; + } + } + } + else { + // Cover DOWN + processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks); + // Search in a cube + for (int y = -1; y <= 1; y++) { + for (int[] dir : directions) { + processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks); + + if (treeFellerReachedThreshold) { + return; + } + } + } + } + + // Recursive call for each log found + for (BlockState futureCenterBlock : futureCenterBlocks) { + if (treeFellerReachedThreshold) { + return; + } + + processTree(futureCenterBlock, treeFellerBlocks); + } + } + + /** + * Handles the durability loss + * + * @param treeFellerBlocks List of blocks to be removed + * @param inHand tool being used + * @return True if the tool can sustain the durability loss + */ + private static boolean handleDurabilityLoss(Set treeFellerBlocks, ItemStack inHand) { + //Treat the NBT tag for unbreakable and the durability enchant differently + if(inHand.getItemMeta() != null && inHand.getItemMeta().isUnbreakable()) { + return true; + } + + short durabilityLoss = 0; + Material type = inHand.getType(); + + for (BlockState blockState : treeFellerBlocks) { + if (BlockUtils.isLog(blockState)) { + durabilityLoss += Config.getInstance().getAbilityToolDamage(); + } + } + + SkillUtils.handleDurabilityChange(inHand, durabilityLoss); + return (inHand.getDurability() < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability())); + } + + /** + * Handle a block addition to the list of blocks to be removed and to the + * list of blocks used for future recursive calls of + * 'processTree()' + * + * @param blockState Block to be added + * @param futureCenterBlocks List of blocks that will be used to call + * 'processTree()' + * @param treeFellerBlocks List of blocks to be removed + * @return true if and only if the given blockState was a Log not already + * in treeFellerBlocks. + */ + private boolean processTreeFellerTargetBlock(BlockState blockState, List futureCenterBlocks, Set treeFellerBlocks) { + if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) { + return false; + } + + // Without this check Tree Feller propagates through leaves until the threshold is hit + if (treeFellerBlocks.size() > treeFellerThreshold) { + treeFellerReachedThreshold = true; + } + + if (BlockUtils.isLog(blockState)) { + treeFellerBlocks.add(blockState); + futureCenterBlocks.add(blockState); + return true; + } + else if (BlockUtils.isLeaves(blockState)) { + treeFellerBlocks.add(blockState); + return false; + } + return false; } /** @@ -111,7 +260,7 @@ public class WoodcuttingManager extends SkillManager { * * @param treeFellerBlocks List of blocks to be dropped */ - private void dropBlocks(Set treeFellerBlocks) { + private void dropTreeFellerLootFromBlocks(Set treeFellerBlocks) { Player player = getPlayer(); int xp = 0; int processedLogCount = 0; @@ -127,16 +276,16 @@ public class WoodcuttingManager extends SkillManager { //TODO: Update this to drop the correct items/blocks via NMS if (material == Material.BROWN_MUSHROOM_BLOCK || material == Material.RED_MUSHROOM_BLOCK) { - xp += Woodcutting.processTreeFellerXPGains(blockState, processedLogCount); + xp += processTreeFellerXPGains(blockState, processedLogCount); Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops()); } else if (mcMMO.getModManager().isCustomLeaf(blockState)) { Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops()); } else { if (BlockUtils.isLog(blockState)) { if (canGetDoubleDrops()) { - Woodcutting.checkForDoubleDrop(blockState); + checkForDoubleDrop(blockState); } - xp += Woodcutting.processTreeFellerXPGains(blockState, processedLogCount); + xp += processTreeFellerXPGains(blockState, processedLogCount); Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops()); } if (BlockUtils.isLeaves(blockState)) { @@ -151,4 +300,59 @@ public class WoodcuttingManager extends SkillManager { applyXpGain(xp, XPGainReason.PVE); } + + /** + * Retrieves the experience reward from logging via Tree Feller + * Experience is reduced per log processed so far + * Experience is only reduced if the config option to reduce Tree Feller XP is set + * Experience per log will not fall below 1 unless the experience for that log is set to 0 in the config + * + * @param blockState Log being broken + * @param woodCount how many logs have given out XP for this tree feller so far + * @return Amount of experience + */ + private static int processTreeFellerXPGains(BlockState blockState, int woodCount) { + int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + + if(rawXP <= 0) + return 0; + + if(ExperienceConfig.getInstance().isTreeFellerXPReduced()) { + int reducedXP = 1 + (woodCount * 5); + rawXP = Math.max(1, rawXP - reducedXP); + return rawXP; + } else { + return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + } + } + + /** + * Retrieves the experience reward from a log + * + * @param blockState Log being broken + * @return Amount of experience + */ + protected static int getExperienceFromLog(BlockState blockState) { + if (mcMMO.getModManager().isCustomLog(blockState)) { + return mcMMO.getModManager().getBlock(blockState).getXpGain(); + } + + return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType()); + } + + /** + * Checks for double drops + * + * @param blockState Block being broken + */ + protected static void checkForDoubleDrop(BlockState blockState) { + if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) { + Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); + } + else { + if (Config.getInstance().getWoodcuttingDoubleDropsEnabled(blockState.getBlockData())) { + Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); + } + } + } } From 51ade5113fea27a714a3a7e569a8932e0f932c17 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 14:50:34 -0700 Subject: [PATCH 13/31] Adjust changelog --- Changelog.txt | 2 ++ .../gmail/nossr50/skills/woodcutting/WoodcuttingManager.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 58a362229..5333b994d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,7 @@ Version 2.1.94 Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big + Updated Japanese locale (thanks snake) + Updated hu_HU locale (thanks andris155) Version 2.1.93 Fixed a bug where players would be told they could not breed summoned animals when the animals weren't summoned (bug didn't actually do anything besides send you a message) diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index f2cc6256b..6f3565fac 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -62,7 +62,7 @@ public class WoodcuttingManager extends SkillManager { && ItemUtils.isAxe(heldItem); } - protected boolean canGetDoubleDrops() { + private boolean canGetDoubleDrops() { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); From 9667eaf0451628d511f276a69d3ecce9f7608aea Mon Sep 17 00:00:00 2001 From: SNAKE0053 <6961187+snake0053@users.noreply.github.com> Date: Wed, 3 Jul 2019 06:51:06 +0900 Subject: [PATCH 14/31] Fix spelling --- src/main/resources/locale/locale_en_US.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 5f6dea6e5..871e173d9 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -219,7 +219,7 @@ Excavation.SubSkill.GigaDrillBreaker.Stat=Giga Drill Breaker Duration Excavation.SubSkill.Archaeology.Name=Archaeology Excavation.SubSkill.Archaeology.Description=Unearth the secrets of the land! High skill levels increase your odds of finding experience orbs when you find treasure! Excavation.SubSkill.Archaeology.Stat=Archaelogy Experience Orb Chance -Excavation.SubSkill.Archaeology.Stat.Extra=Archaeoloy Experience Orb Amount +Excavation.SubSkill.Archaeology.Stat.Extra=Archaeology Experience Orb Amount Excavation.Listener=Excavation: Excavation.SkillName=EXCAVATION Excavation.Skills.GigaDrillBreaker.Off=**Giga Drill Breaker has worn off** From f7c0c9beb796c92a4a58f7576616a299035efa4b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 16:22:56 -0700 Subject: [PATCH 15/31] Add new mcMMO devs to readme.md and plugin.yml --- README.md | 27 +++++++++++++++------------ src/main/resources/plugin.yml | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index dc8f66c28..64ac62516 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # mcMMO -## The RPG lovers mod +## The #1 RPG Mod for Minecraft ## Website I'm working on a brand new website for mcMMO You can check it out here http://www.mcmmo.org -Spigot Resource: https://www.spigotmc.org/resources/official-mcmmo-original-author-returns.64348/ + +Spigot Resource: https://spigot.mcmmo.org I plan to post links to our new wiki (its still under development), downloads, and dev blogs there. - ### Builds Currently, you can obtain our builds via the Spigot resource page: http://spigot.mcmmo.org @@ -17,16 +17,16 @@ Currently, you can obtain our builds via the Spigot resource page: http://spigot The goal of mcMMO is to take core Minecraft game mechanics and expand them into an extensive and quality RPG experience. Everything in mcMMO has been carefully thought out and is constantly being improved upon. Currently, mcMMO adds fourteen unique skills to train and level in. Each of these skills is highly customizable through our configuration files, allowing server admins to tweak mcMMO to best suit the needs of his or her server. Know that the mcMMO team is dedicated to providing an ever-evolving experience, and that we carefully read all feedback and bug reports in order to evaluate and balance the mechanics of mcMMO in every update. ## About the Team -In December 2018 nossr50 returned as project lead for mcMMO once again to develop and improve mcMMO. -The mcMMO team currently has two members, nossr50 (lead) and t00thpick1 (classic maintainer). -mcMMO is currently developed almost entirely by nossr50, many thanks go out to the many developers who have worked on the project over the years. - -### Project Lead & Founder +In December 2018, the original author and creator of mcMMO (nossr50) returned and took over the role of project lead once again, to develop and improve mcMMO. +#### Project Lead & Founder [![nossr50](http://www.gravatar.com/avatar/f2ee41eedfd645fb4a3a2c8f6cb1b18c.png)](https://github.com/nossr50) -Other mcMMO Projects +#### mcMMO Devs +[![nossr50](http://www.gravatar.com/avatar/f2ee41eedfd645fb4a3a2c8f6cb1b18c.png)](https://github.com/nossr50) +[![kashike](https://secure.gravatar.com/avatar/b5e86d6d443b957fd5cdee55501f3799.png)](https://github.com/kashike) +[![electronicboy](https://secure.gravatar.com/avatar/44759c38d311ce09596de6a2d5b88036.png)](https://github.com/electronicboy) -### Classic Maintainer +#### Classic Maintainer [![t00thpick1](http://www.gravatar.com/avatar/ee23c7794a0c40120c3474287c7bce06.png)](https://github.com/t00thpick1) ## Former Team Members @@ -50,10 +50,13 @@ mcMMO uses Maven 3 to manage dependencies, packaging, and shading of necessary c The typical command used to build mcMMO is: `mvn clean package install` Required Libraries: -* Bukkit +* Spigot * JUnit * WorldGuard 7 * bStats Bukkit -http://spigot.mcmmo.org for more up to date information. +https://spigot.mcmmo.org for more up to date information. + +Resource Page + https://www.spigotmc.org/resources/official-mcmmo-original-author-returns.64348/ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e29bef197..587fa7f0d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,7 +11,7 @@ description: > in order to evaluate and balance the mechanics of mcMMO in every update. author: nossr50 -authors: [GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking] +authors: [GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking, electronicboy, kashike] website: https://www.mcmmo.org main: com.gmail.nossr50.mcMMO softdepend: [WorldGuard, CombatTag, HealthBar] From 1307169d8b296385d77b22d3ea2ab8d617d5e5b1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 17:29:33 -0700 Subject: [PATCH 16/31] Debug Stick is now replaced by /mmodebug --- Changelog.txt | 8 ++++++ .../gmail/nossr50/commands/McmmoCommand.java | 1 + .../nossr50/commands/admin/PlayerDebug.java | 13 ---------- .../commands/admin/PlayerDebugCommand.java | 25 +++++++++++++++++++ .../nossr50/datatypes/player/McMMOPlayer.java | 15 +++++++++++ .../nossr50/listeners/BlockListener.java | 15 +++++------ .../commands/CommandRegistrationManager.java | 11 ++++++++ .../util/player/NotificationManager.java | 10 ++++++++ .../resources/locale/locale_en_US.properties | 6 ++++- src/main/resources/plugin.yml | 3 +++ 10 files changed, 86 insertions(+), 21 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/commands/admin/PlayerDebug.java create mode 100644 src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java diff --git a/Changelog.txt b/Changelog.txt index 5333b994d..c541a9675 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,13 @@ Version 2.1.94 + 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big + New command /mmodebug (or /mcmmodebugmode) - Prints useful information when players punch blocks while they are in debug mode + mcMMO no longer prints debug information when you attack stuff with the debug stick, use the new command (/mmodebug) instead + Added locale string 'mcMMO.Description.FormerDevs' + Added locale string 'mcMMO.Template.Prefix' + Added locale string 'Commands.Mmodebug.Toggle' + Added locale string 'Commands.Description.mmodebug' + Tweaked locale string 'mcMMO.Description' Updated Japanese locale (thanks snake) Updated hu_HU locale (thanks andris155) diff --git a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java index 0dbe2838c..16280c9d0 100644 --- a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java @@ -23,6 +23,7 @@ public class McmmoCommand implements CommandExecutor { String description = LocaleLoader.getString("mcMMO.Description"); String[] mcSplit = description.split(","); sender.sendMessage(mcSplit); + sender.sendMessage(LocaleLoader.getString("mcMMO.Description.FormerDevs")); if (Config.getInstance().getDonateMessageEnabled()) { sender.sendMessage(LocaleLoader.getString("MOTD.Donate")); diff --git a/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebug.java b/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebug.java deleted file mode 100644 index 9ced7e818..000000000 --- a/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebug.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.gmail.nossr50.commands.admin; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; - -public class PlayerDebug implements CommandExecutor { - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - return false; - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java b/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java new file mode 100644 index 000000000..aa2726311 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java @@ -0,0 +1,25 @@ +package com.gmail.nossr50.commands.admin; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class PlayerDebugCommand implements CommandExecutor { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if(sender instanceof Player) { + McMMOPlayer mcMMOPlayer = UserManager.getPlayer((Player) sender); + mcMMOPlayer.toggleDebugMode(); //Toggle debug mode + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.Mmodebug.Toggle", String.valueOf(mcMMOPlayer.isDebugMode())); + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index f4986d5f4..219b1df16 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -81,6 +81,7 @@ public class McMMOPlayer { private boolean partyChatMode; private boolean adminChatMode; private boolean displaySkillNotifications = true; + private boolean debugMode; private boolean abilityUse = true; private boolean godMode; @@ -139,6 +140,8 @@ public class McMMOPlayer { } experienceBarManager = new ExperienceBarManager(this); + + debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off } public String getPlayerName() { @@ -437,6 +440,18 @@ public class McMMOPlayer { public void togglePartyChatSpying() { chatSpy = !chatSpy;} + /* + * Debug Mode Flags + */ + + public boolean isDebugMode() { + return debugMode; + } + + public void toggleDebugMode() { + debugMode = !debugMode; + } + /* * Skill notifications */ diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index e83c9f96f..dc27a1fac 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -30,10 +30,7 @@ import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Tag; +import org.bukkit.*; import org.bukkit.block.*; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -619,14 +616,16 @@ public class BlockListener implements Listener { debugStickDump(player, blockState); } - public void debugStickDump(Player player, BlockState blockState) { + //TODO: Rewrite this + //TODO: Convert into locale strings + private void debugStickDump(Player player, BlockState blockState) { //Profile not loaded if(UserManager.getPlayer(player) == null) { return; } - if(player.getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) + if(UserManager.getPlayer(player).isDebugMode()) { if(mcMMO.getPlaceStore().isTrue(blockState)) player.sendMessage("[mcMMO DEBUG] This block is not natural and does not reward treasures/XP"); @@ -667,10 +666,12 @@ public class BlockListener implements Listener { if(ExperienceConfig.getInstance().isExperienceBarsEnabled()) player.sendMessage("[mcMMO DEBUG] XP bars are enabled, however you should check per-skill settings to make sure those are enabled."); + + player.sendMessage(ChatColor.RED+"You can turn this debug info off by typing "+ChatColor.GOLD+"/mmodebug"); } } - public void cleanupAbilityTools(Player player, McMMOPlayer mcMMOPlayer, BlockState blockState, ItemStack heldItem) { + private void cleanupAbilityTools(Player player, McMMOPlayer mcMMOPlayer, BlockState blockState, ItemStack heldItem) { if (HiddenConfig.getInstance().useEnchantmentBuffs()) { if ((ItemUtils.isPickaxe(heldItem) && !mcMMOPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER)) || (ItemUtils.isShovel(heldItem) && !mcMMOPlayer.getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER))) { SkillUtils.removeAbilityBuff(heldItem); diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 2d3ab2360..b69f486e8 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.util.commands; import com.gmail.nossr50.commands.*; import com.gmail.nossr50.commands.admin.McmmoReloadLocaleCommand; +import com.gmail.nossr50.commands.admin.PlayerDebugCommand; import com.gmail.nossr50.commands.chat.AdminChatCommand; import com.gmail.nossr50.commands.chat.McChatSpy; import com.gmail.nossr50.commands.chat.PartyChatCommand; @@ -150,6 +151,15 @@ public final class CommandRegistrationManager { command.setExecutor(new MmoInfoCommand()); } + private static void registerMmoDebugCommand() { + PluginCommand command = mcMMO.p.getCommand("mmodebug"); + command.setDescription(LocaleLoader.getString("Commands.Description.mmodebug")); + command.setPermission(null); //No perm required to save support headaches + command.setPermissionMessage(permissionsMessage); + command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mmodebug")); + command.setExecutor(new PlayerDebugCommand()); + } + private static void registerMcChatSpyCommand() { PluginCommand command = mcMMO.p.getCommand("mcchatspy"); command.setDescription(LocaleLoader.getString("Commands.Description.mcchatspy")); @@ -413,6 +423,7 @@ public final class CommandRegistrationManager { public static void registerCommands() { // Generic Commands registerMmoInfoCommand(); + registerMmoDebugCommand(); registerMcImportCommand(); registerMcabilityCommand(); registerMcgodCommand(); diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index 09d9aa697..2bd02aa6a 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -76,6 +76,16 @@ public class NotificationManager { player.sendMessage(preColoredString); } + public static void sendPlayerInformationChatOnlyPrefixed(Player player, String key, String... values) + { + if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) + return; + + String preColoredString = LocaleLoader.getString(key, (Object[]) values); + String prefixFormattedMessage = LocaleLoader.getString("mcMMO.Template.Prefix", preColoredString); + player.sendMessage(prefixFormattedMessage); + } + public static void sendPlayerInformation(Player player, NotificationType notificationType, String key, String... values) { if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 871e173d9..5c2e100c4 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -59,6 +59,7 @@ Anvil.SingleItemStack=[[RED]]You cannot salvage or repair item stacks that have #DO NOT USE COLOR CODES IN THE JSON KEYS #COLORS ARE DEFINED IN advanced.yml IF YOU WISH TO CHANGE THEM +mcMMO.Template.Prefix=[[GOLD]]([[GREEN]]mcMMO[[GOLD]]) [[GRAY]]{0} # BEGIN STYLING Ability.Generic.Refresh=[[GREEN]]**ABILITIES REFRESHED!** Ability.Generic.Template.Lock=[[GRAY]]{0} @@ -560,7 +561,8 @@ Combat.TargetDazed=Target was [[DARK_RED]]Dazed Combat.TouchedFuzzy=[[DARK_RED]]Touched Fuzzy. Felt Dizzy. #COMMANDS ##generic -mcMMO.Description=[[DARK_AQUA]]About the [[YELLOW]]mcMMO[[DARK_AQUA]] Project:,[[GOLD]]mcMMO is an [[RED]]open source[[GOLD]] RPG mod created in February 2011,[[GOLD]]by [[BLUE]]nossr50[[GOLD]]. The goal is to provide a quality RPG experience.,[[DARK_AQUA]]Tips:,[[GOLD]] - [[GREEN]]Use [[RED]]/mcmmo help[[GREEN]] to see commands,[[GOLD]] - [[GREEN]]Type [[RED]]/SKILLNAME[[GREEN]] to see detailed skill info,[[DARK_AQUA]]Developers:,[[GOLD]] - [[GREEN]]nossr50 [[BLUE]](Founder & Project Lead),[[GOLD]] - [[GREEN]]GJ [[BLUE]](Former Project Lead),[[GOLD]] - [[GREEN]]NuclearW [[BLUE]](Developer),[[GOLD]] - [[GREEN]]bm01 [[BLUE]](Developer),[[GOLD]] - [[GREEN]]TfT_02 [[BLUE]](Developer),[[GOLD]] - [[GREEN]]Glitchfinder [[BLUE]](Developer),[[GOLD]] - [[GREEN]]t00thpick1 [[BLUE]](Developer),[[DARK_AQUA]]Useful Links:,[[GOLD]] - [[GREEN]]https://github.com/mcMMO-Dev/mcMMO/issues[[GOLD]] Bug Reporting,[[GOLD]] - [[GREEN]]https://discord.gg/EJGVanb [[GOLD]] Official Discord +mcMMO.Description=[[DARK_AQUA]]About the [[YELLOW]]mcMMO[[DARK_AQUA]] Project:,[[GOLD]]mcMMO is an [[RED]]open source[[GOLD]] RPG mod created in February 2011,[[GOLD]]by [[BLUE]]nossr50[[GOLD]]. The goal is to provide a quality RPG experience.,[[DARK_AQUA]]Tips:,[[GOLD]] - [[GREEN]]Use [[RED]]/mcmmo help[[GREEN]] to see commands,[[GOLD]] - [[GREEN]]Type [[RED]]/SKILLNAME[[GREEN]] to see detailed skill info,[[DARK_AQUA]]Developers:,[[GOLD]] - [[GREEN]]nossr50 [[BLUE]](Creator & Project Lead),[[GOLD]] - [[GREEN]]electronicboy [[BLUE]](Dev),[[GOLD]] - [[GREEN]]kashike [[BLUE]](Dev),[[GOLD]] - [[GREEN]]t00thpick1 [[BLUE]](Classic Maintainer) +mcMMO.Description.FormerDevs=[[DARK_AQUA]]Former Devs: [[GREEN]]GJ, NuclearW, bm01, TfT_02, Glitchfinder Commands.addlevels.AwardAll.1=[[GREEN]]You were awarded {0} levels in all skills! Commands.addlevels.AwardAll.2=All skills have been modified for {0}. Commands.addlevels.AwardSkill.1=[[GREEN]]You were awarded {0} levels in {1}! @@ -725,6 +727,7 @@ Commands.MmoInfo.DetailsHeader=[[DARK_AQUA]]-=[]=====[][[GREEN]] Details [[DARK_ Commands.MmoInfo.OldSkill=[[GRAY]]mcMMO skills are being converted into an improved modular skill system, unfortunately this skill has not been converted yet and lacks detailed stats. The new system will allow for faster release times for new mcMMO skills and greater flexibility with existing skills. Commands.MmoInfo.Mechanics=[[DARK_AQUA]]-=[]=====[][[GOLD]] Mechanics [[DARK_AQUA]][]=====[]=- Commands.MmoInfo.Stats=STATS: {0} +Commands.Mmodebug.Toggle=mcMMO Debug Mode is now [[GOLD]]{0}[[GRAY]], use this command again to toggle. With debug mode true, you can punch blocks to print useful information used for support. mcMMO.NoInvites=[[RED]]You have no invites at this time mcMMO.NoPermission=[[DARK_RED]]Insufficient permissions. mcMMO.NoSkillNote=[[DARK_GRAY]]If you don't have access to a skill it will not be shown here. @@ -1059,6 +1062,7 @@ Commands.Description.mcscoreboard=Manage your mcMMO Scoreboard Commands.Description.mcstats=Show your mcMMO levels and XP Commands.Description.mctop=Show mcMMO leader boards Commands.Description.mmoedit=Edit mcMMO levels for a user +Commands.Description.mmodebug=Toggle a debug mode which prints useful information when you hit blocks Commands.Description.mmoupdate=Migrate mcMMO database from an old database into the current one Commands.Description.mcconvert=Converts database types or experience formula types Commands.Description.mmoshowdb=Show the name of the current database type (for later use with /mmoupdate) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 587fa7f0d..04dbc2e41 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -19,6 +19,9 @@ load: STARTUP api-version: 1.13 commands: + mmodebug: + aliases: [mcmmodebugmode] + description: Toggles a debug mode which will print useful information to chat mmoinfo: aliases: [mcinfo] description: Info pages for mcMMO From 02c1ce749c49f988098a05a4fa23914aaf2bc96f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 2 Jul 2019 17:29:57 -0700 Subject: [PATCH 17/31] 2.1.94 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6c0c5e07d..a82326bc2 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.94-SNAPSHOT + 2.1.94 mcMMO https://github.com/mcMMO-Dev/mcMMO From 304a942f51153b8256a7387bf19559dbc4c16240 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Jul 2019 05:51:41 -0700 Subject: [PATCH 18/31] Fixed a bug preventing wandering traders from granting XP --- Changelog.txt | 3 ++ pom.xml | 2 +- .../java/com/gmail/nossr50/util/Misc.java | 37 +++++++++++++++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index c541a9675..0f04fd96c 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.95 + Fixed a bug preventing Wandering Traders from granting XP + Version 2.1.94 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big diff --git a/pom.xml b/pom.xml index a82326bc2..b19bd57e9 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.94 + 2.1.95-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index ff892d659..1a17e2727 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -40,17 +40,40 @@ public final class Misc { private Misc() {}; + /** + * Determines if an entity is an NPC but not a villager + * This method aims to establish compatibility between mcMMO and other plugins which create "NPCs" + * + * It does this by checking the following + * 1) The entity is not a Villager + * 2) The entity can be considered an NPC + * + * In this context, an NPC is a bit hard to define. Various plugins determine what an NPC is in different ways. + * @see Misc::isNPCIncludingVillagers + * @param entity target entity + * @return true if the entity is not a Villager and is not a "NPC" + */ public static boolean isNPCEntityExcludingVillagers(Entity entity) { - return (entity == null - || (entity.hasMetadata("NPC") && !(entity instanceof Villager)) - || (entity instanceof NPC && !(entity instanceof Villager)) - || entity.getClass().getName().equalsIgnoreCase("cofh.entity.PlayerFake")); + return (!isVillager(entity) + && isNPCIncludingVillagers(entity)); //Compatibility with some mod.. } - public static boolean isNPCIncludingVillagers(Player entity) { + public static boolean isNPCClassType(Entity entity) { + return entity instanceof NPC; + } + + public static boolean hasNPCMetadataTag(Entity entity) { + return entity.hasMetadata("NPC"); + } + + public static boolean isVillager(Entity entity) { + return (entity instanceof AbstractVillager); + } + + public static boolean isNPCIncludingVillagers(Entity entity) { return (entity == null - || (entity.hasMetadata("NPC")) - || (entity instanceof NPC) + || (hasNPCMetadataTag(entity)) + || (isNPCClassType(entity)) || entity.getClass().getName().equalsIgnoreCase("cofh.entity.PlayerFake")); } From 0b2d0fa3322a6d7eff70cb6322191f8313f4eb10 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Jul 2019 06:14:54 -0700 Subject: [PATCH 19/31] Make the last bug fix compatible with 1.13 --- Changelog.txt | 1 + src/main/java/com/gmail/nossr50/util/Misc.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 0f04fd96c..5de3473d8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,7 @@ Version 2.1.95 Fixed a bug preventing Wandering Traders from granting XP + Version 2.1.94 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 1a17e2727..945b39eef 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -67,7 +67,9 @@ public final class Misc { } public static boolean isVillager(Entity entity) { - return (entity instanceof AbstractVillager); + String entityType = entity.getType().toString(); + //This weird code is for 1.13 & 1.14 compatibility + return entityType.equalsIgnoreCase("wandering_trader") || entity instanceof Villager; } public static boolean isNPCIncludingVillagers(Entity entity) { From 39a1a07a7d73de9968919213a8338b14d03801d3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Jul 2019 06:20:44 -0700 Subject: [PATCH 20/31] Add missing Chorus_Flower xp entry for Herbalism to experience.yml --- Changelog.txt | 2 +- src/main/resources/experience.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 5de3473d8..1685d39b5 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,6 @@ Version 2.1.95 Fixed a bug preventing Wandering Traders from granting XP - + Added missing 'Chorus_Flower' entry to herbalism in experience.yml (update your config manually or delete the file to regenerate it) Version 2.1.94 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 94052a786..01be9f9f1 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -317,6 +317,7 @@ Experience_Values: Cactus: 30 Carrots_Ripe: 50 Chorus_Flower_Ripe: 25 + Chorus_Flower: 25 Chorus_Plant: 1 Cocoa_Ripe: 30 Wheat_Ripe: 50 From ec44c99076ad805098d9ea3035d4fccff17d8545 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 01:42:57 -0700 Subject: [PATCH 21/31] Many Herbalism bug fixes --- Changelog.txt | 11 + .../nossr50/datatypes/BlockSnapshot.java | 30 ++ .../skills/subskills/acrobatics/Roll.java | 11 + .../nossr50/listeners/BlockListener.java | 4 +- .../gmail/nossr50/listeners/SelfListener.java | 16 + .../skills/DelayedHerbalismXPCheckTask.java | 23 + .../nossr50/skills/herbalism/Herbalism.java | 144 ------ .../skills/herbalism/HerbalismManager.java | 454 +++++++++++++++--- .../com/gmail/nossr50/util/BlockUtils.java | 4 +- .../gmail/nossr50/util/MaterialMapStore.java | 46 +- src/main/resources/config.yml | 2 + src/main/resources/experience.yml | 17 +- 12 files changed, 533 insertions(+), 229 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java create mode 100644 src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java diff --git a/Changelog.txt b/Changelog.txt index 1685d39b5..45966f184 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,17 @@ Version 2.1.95 + Added missing Chorus_Fruit & Chorus_Plant entries to Herbalism's Bonus Drops in config.yml (See notes) + Added 'Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart' to Herbalism in experience.yml (See notes) Fixed a bug preventing Wandering Traders from granting XP + Fixed a bug that prevented Chorus Tree's from giving full XP if you broke anything other than the bottom block + Fixed a bug which could cause Large Fern's to reward less XP + Fixed a bug where certain herbalism crops could have fewer than intended bonus drops Added missing 'Chorus_Flower' entry to herbalism in experience.yml (update your config manually or delete the file to regenerate it) + Added some debug messages about XP gains if you are in debug mode + Added some debug messages for Acrobatics if you are in debug mode + + NOTES: + Add 'Chorus_Fruit' and 'Chorus_Plant' under Bonus_Drops.Herbalism in config.yml or you will not be getting double drops for Chorus Fruit. + You shouldn't need to add "Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart" to your experience file, it seems that file updates automatically for missing entries. Version 2.1.94 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this diff --git a/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java b/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java new file mode 100644 index 000000000..83e572b41 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/BlockSnapshot.java @@ -0,0 +1,30 @@ +package com.gmail.nossr50.datatypes; + +import org.bukkit.Material; +import org.bukkit.block.Block; + +/** + * Contains a snapshot of a block at a specific moment in time + * Used to check before/after type stuff + */ +public class BlockSnapshot { + private final Material oldType; + private Block blockRef; + + public BlockSnapshot(Material oldType, Block blockRef) { + this.oldType = oldType; + this.blockRef = blockRef; + } + + public Material getOldType() { + return oldType; + } + + public Block getBlockRef() { + return blockRef; + } + + public boolean hasChangedType() { + return oldType != blockRef.getState().getType(); + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index d889286ed..78534523f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -274,12 +274,23 @@ public class Roll extends AcrobaticsSubSkill { return false; } + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + if (player.getInventory().getItemInMainHand().getType() == Material.ENDER_PEARL || player.isInsideVehicle()) { + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle"); + } return true; } if(UserManager.getPlayer(player).getAcrobaticsManager().hasFallenInLocationBefore(getBlockLocation(player))) + { + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Fallen in location before"); + } + return true; + } return false; //NOT EXPLOITING } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index dc27a1fac..1f43bbfbe 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -343,7 +343,7 @@ public class BlockListener implements Listener { * Instead, we check it inside the drops handler. */ if (PrimarySkillType.HERBALISM.getPermissions(player)) { - herbalismManager.herbalismBlockCheck(blockState); + herbalismManager.processHerbalismBlockBreakEvent(event); } } @@ -574,7 +574,7 @@ public class BlockListener implements Listener { * We don't need to check permissions here because they've already been checked for the ability to even activate. */ if (mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState)) { - if (mcMMOPlayer.getHerbalismManager().processGreenTerra(blockState)) { + if (mcMMOPlayer.getHerbalismManager().processGreenTerraBlockConversion(blockState)) { blockState.update(true); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index bf1c7b461..1d20e2f7d 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -75,6 +75,11 @@ public class SelfListener implements Listener { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); PrimarySkillType primarySkillType = event.getSkill(); + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage(event.getSkill().toString() + " XP Gained"); + mcMMOPlayer.getPlayer().sendMessage("Incoming Raw XP: "+event.getRawXpGained()); + } + //WorldGuard XP Check if(event.getXpGainReason() == XPGainReason.PVE || event.getXpGainReason() == XPGainReason.PVP || @@ -87,6 +92,10 @@ public class SelfListener implements Listener { { event.setRawXpGained(0); event.setCancelled(true); + + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("No WG XP Flag - New Raw XP: "+event.getRawXpGained()); + } } } } @@ -112,6 +121,9 @@ public class SelfListener implements Listener { int threshold = ExperienceConfig.getInstance().getDiminishedReturnsThreshold(primarySkillType); if (threshold <= 0 || !ExperienceConfig.getInstance().getDiminishedReturnsEnabled()) { + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained()); + } // Diminished returns is turned off return; } @@ -156,6 +168,10 @@ public class SelfListener implements Listener { } } + + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained()); + } } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java new file mode 100644 index 000000000..3ecc03747 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.runnables.skills; + +import com.gmail.nossr50.datatypes.BlockSnapshot; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; + +public class DelayedHerbalismXPCheckTask extends BukkitRunnable { + + private final McMMOPlayer mcMMOPlayer; + private final ArrayList chorusBlocks; + + public DelayedHerbalismXPCheckTask(McMMOPlayer mcMMOPlayer, ArrayList chorusBlocks) { + this.mcMMOPlayer = mcMMOPlayer; + this.chorusBlocks = chorusBlocks; + } + + @Override + public void run() { + mcMMOPlayer.getHerbalismManager().awardXPForBlockSnapshots(chorusBlocks); + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java b/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java index 79e97d2df..b486db4f2 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/Herbalism.java @@ -1,15 +1,10 @@ package com.gmail.nossr50.skills.herbalism; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.skills.SkillUtils; import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; -import java.util.HashSet; - public class Herbalism { /** @@ -43,145 +38,6 @@ public class Herbalism { } } - private static int calculateChorusPlantDrops(Block target, boolean triple, HerbalismManager herbalismManager) { - return calculateChorusPlantDropsRecursive(target, new HashSet<>(), triple, herbalismManager); - } - - private static int calculateChorusPlantDropsRecursive(Block target, HashSet traversed, boolean triple, HerbalismManager herbalismManager) { - if (target.getType() != Material.CHORUS_PLANT) - return 0; - - // Prevent any infinite loops, who needs more than 64 chorus anyways - if (traversed.size() > 64) - return 0; - - if (!traversed.add(target)) - return 0; - - int dropAmount = 0; - - if (mcMMO.getPlaceStore().isTrue(target)) - mcMMO.getPlaceStore().setFalse(target); - else - { - dropAmount++; - - if(herbalismManager.checkDoubleDrop(target.getState())) - BlockUtils.markDropsAsBonus(target.getState(), triple); - } - - for (BlockFace blockFace : new BlockFace[] { BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST ,BlockFace.WEST}) - dropAmount += calculateChorusPlantDropsRecursive(target.getRelative(blockFace, 1), traversed, triple, herbalismManager); - - return dropAmount; - } - - /** - * Calculate the drop amounts for multi block plants based on the blocks - * relative to them. - * - * @param blockState - * The {@link BlockState} of the bottom block of the plant - * @return the number of bonus drops to award from the blocks in this plant - */ - protected static int countAndMarkDoubleDropsMultiBlockPlant(BlockState blockState, boolean triple, HerbalismManager herbalismManager) { - Block block = blockState.getBlock(); - Material blockType = blockState.getType(); - int dropAmount = 0; - int bonusDropAmount = 0; - int bonusAdd = triple ? 2 : 1; - - if (blockType == Material.CHORUS_PLANT) { - dropAmount = 1; - - if (block.getRelative(BlockFace.DOWN, 1).getType() == Material.END_STONE) { - dropAmount = calculateChorusPlantDrops(block, triple, herbalismManager); - } - } else { - //Check the block itself first - if(!mcMMO.getPlaceStore().isTrue(block)) - { - dropAmount++; - - if(herbalismManager.checkDoubleDrop(blockState)) - bonusDropAmount+=bonusAdd; - } else { - mcMMO.getPlaceStore().setFalse(blockState); - } - - // Handle the two blocks above it - cacti & sugar cane can only grow 3 high naturally - for (int y = 1; y < 255; y++) { - Block relativeBlock = block.getRelative(BlockFace.UP, y); - - if (relativeBlock.getType() != blockType) { - break; - } - - if (mcMMO.getPlaceStore().isTrue(relativeBlock)) { - mcMMO.getPlaceStore().setFalse(relativeBlock); - } else { - dropAmount++; - - if(herbalismManager.checkDoubleDrop(relativeBlock.getState())) - bonusDropAmount+=bonusAdd; - } - } - } - - //Mark the original block for bonus drops - BlockUtils.markDropsAsBonus(blockState, bonusDropAmount); - - return dropAmount; - } - - /** - * Calculate the drop amounts for kelp plants based on the blocks - * relative to them. - * - * @param blockState - * The {@link BlockState} of the bottom block of the plant - * @return the number of bonus drops to award from the blocks in this plant - */ - protected static int countAndMarkDoubleDropsKelp(BlockState blockState, boolean triple, HerbalismManager herbalismManager) { - Block block = blockState.getBlock(); - - int kelpMaxHeight = 255; - int amount = 1; - - // Handle the two blocks above it - cacti & sugar cane can only grow 3 high naturally - for (int y = 1; y < kelpMaxHeight; y++) { - Block relativeUpBlock = block.getRelative(BlockFace.UP, y); - - if(!isKelp(relativeUpBlock)) - break; - - amount += 1; - - if(herbalismManager.checkDoubleDrop(relativeUpBlock.getState())) - BlockUtils.markDropsAsBonus(relativeUpBlock.getState(), triple); - - } - - return amount; - } - - private static int addKelpDrops(int dropAmount, Block relativeBlock) { - if (isKelp(relativeBlock) && !mcMMO.getPlaceStore().isTrue(relativeBlock)) { - dropAmount++; - } else { - mcMMO.getPlaceStore().setFalse(relativeBlock); - } - - return dropAmount; - } - - private static boolean isKelp(Block relativeBlock) { - Material kelptype_1 = Material.KELP_PLANT; - Material kelptype_2 = Material.KELP; - - return relativeBlock.getType() == kelptype_1 || relativeBlock.getType() == kelptype_2; - } - /** * Convert blocks affected by the Green Thumb & Green Terra abilities. * diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 4f20b62a1..234b20395 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -3,9 +3,10 @@ package com.gmail.nossr50.skills.herbalism; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; +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.mods.CustomBlock; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; @@ -13,6 +14,7 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.datatypes.treasure.HylianTreasure; import com.gmail.nossr50.mcMMO; +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.*; @@ -24,13 +26,20 @@ import com.gmail.nossr50.util.skills.SkillActivationType; import com.gmail.nossr50.util.skills.SkillUtils; 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.block.data.BlockData; import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.metadata.FixedMetadataValue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; public class HerbalismManager extends SkillManager { @@ -38,10 +47,6 @@ public class HerbalismManager extends SkillManager { super(mcMMOPlayer, PrimarySkillType.HERBALISM); } - public boolean canBlockCheck() { - return !(Config.getInstance().getHerbalismPreventAFK() && getPlayer().isInsideVehicle()); - } - public boolean canGreenThumbBlock(BlockState blockState) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.HERBALISM_GREEN_THUMB)) return false; @@ -78,7 +83,7 @@ public class HerbalismManager extends SkillManager { return mcMMOPlayer.getToolPreparationMode(ToolType.HOE) && Permissions.greenTerra(getPlayer()); } - public boolean canGreenTerraPlant() { + public boolean isGreenTerraActive() { return mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA); } @@ -98,7 +103,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 */ - public boolean processGreenTerra(BlockState blockState) { + public boolean processGreenTerraBlockConversion(BlockState blockState) { Player player = getPlayer(); if (!Permissions.greenThumbBlock(player, blockState.getType())) { @@ -120,63 +125,398 @@ public class HerbalismManager extends SkillManager { } /** - * @param blockState The {@link BlockState} to check ability activation for + * Handles herbalism abilities and XP rewards from a BlockBreakEvent + * @param blockBreakEvent The Block Break Event to process */ - public void herbalismBlockCheck(BlockState blockState) { + public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) { Player player = getPlayer(); - Material material = blockState.getType(); - boolean oneBlockPlant = isOneBlockPlant(material); - // Prevents placing and immediately breaking blocks for exp - if (oneBlockPlant && mcMMO.getPlaceStore().isTrue(blockState)) { + if (Config.getInstance().getHerbalismPreventAFK() && player.isInsideVehicle()) { return; } - if (!canBlockCheck()) { - 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 + */ - int amount; - int xp; - boolean greenTerra = mcMMOPlayer.getAbilityMode(skill.getAbility()); + //Grab all broken blocks + HashSet brokenBlocks = getBrokenHerbalismBlocks(blockBreakEvent); - if (mcMMO.getModManager().isCustomHerbalismBlock(blockState)) { - CustomBlock customBlock = mcMMO.getModManager().getBlock(blockState); - xp = customBlock.getXpGain(); - - if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && customBlock.isDoubleDropEnabled()) { - if(checkDoubleDrop(blockState)) - BlockUtils.markDropsAsBonus(blockState, greenTerra); - } - } - else { - xp = ExperienceConfig.getInstance().getXp(skill, blockState.getBlockData()); - - if (!oneBlockPlant) { - //Kelp is actually two blocks mixed together - if(material == Material.KELP_PLANT || material == Material.KELP) { - amount = Herbalism.countAndMarkDoubleDropsKelp(blockState, greenTerra,this); - } else { - amount = Herbalism.countAndMarkDoubleDropsMultiBlockPlant(blockState, greenTerra, this); - } - - xp *= amount; - } else { - /* MARK SINGLE BLOCK CROP FOR DOUBLE DROP */ - if(checkDoubleDrop(blockState)) - BlockUtils.markDropsAsBonus(blockState, greenTerra); - } - - if (Permissions.greenThumbPlant(player, material)) { - processGreenThumbPlants(blockState, greenTerra); - } - } - - applyXpGain(xp, XPGainReason.PVE); + //Handle rewards, xp, ability interactions, etc + processHerbalismOnBlocksBroken(blockBreakEvent, brokenBlocks); } - public boolean isOneBlockPlant(Material material) { - return !mcMMO.getMaterialMapStore().isMultiBlock(material); + /** + * Process rewards for a set of plant blocks for Herbalism + * @param blockBreakEvent the block break event + * @param brokenPlants plant blocks to process + */ + private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet brokenPlants) { + BlockState originalBreak = blockBreakEvent.getBlock().getState(); + + //TODO: The design of Green Terra needs to change, this is a mess + if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { + processGreenThumbPlants(originalBreak, isGreenTerraActive()); + } + + /* + * Mark blocks for double drops + * Be aware of the hacky interactions we are doing with Chorus Plants + */ + checkDoubleDropsOnBrokenPlants(brokenPlants); + + //It would take an expensive algorithm to predict which parts of a Chorus Tree will break as a result of root break + //So this hacky method is used instead + ArrayList delayedChorusBlocks = new ArrayList<>(); //Blocks that will be checked in future ticks + HashSet noDelayPlantBlocks = new HashSet<>(); //Blocks that will be checked immediately + + for(Block brokenPlant : brokenPlants) { + /* + * This check is to make XP bars appear to work properly with Chorus Trees by giving XP for the originalBreak immediately instead of later + */ + if(brokenPlant.getLocation().equals(originalBreak.getBlock().getLocation())) { + //If its the same block as the original, we are going to directly check it for being a valid XP gain and add it to the nonChorusBlocks list even if its a chorus block + //This stops a delay from happening when bringing up the XP bar for chorus trees + if(!mcMMO.getPlaceStore().isTrue(originalBreak)) { + //Even if its a chorus block, the original break will be moved to nonChorusBlocks for immediate XP rewards + noDelayPlantBlocks.add(brokenPlant); + } else { + if(isChorusTree(brokenPlant.getType())) { + //If its a chorus tree AND it was marked as true in the placestore then we add this block to the list of chorus blocks + delayedChorusBlocks.add(new BlockSnapshot(brokenPlant.getType(), brokenPlant)); + } else { + noDelayPlantBlocks.add(brokenPlant); //If its not a chorus plant that was marked as unnatural but it was marked unnatural, put it in the nodelay list to be handled + } + } + } else if(isChorusTree(brokenPlant.getType())) { + //Chorus Blocks get checked for XP several ticks later to avoid expensive calculations + delayedChorusBlocks.add(new BlockSnapshot(brokenPlant.getType(), brokenPlant)); + } else { + noDelayPlantBlocks.add(brokenPlant); + } + } + + //Give out XP to the non-chorus blocks + if(noDelayPlantBlocks.size() > 0) { + //Note: Will contain 1 chorus block if the original block was a chorus block, this is to prevent delays for the XP bar + awardXPForPlantBlocks(noDelayPlantBlocks); + } + + if(delayedChorusBlocks.size() > 0) { + //Check XP for chorus blocks + DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask(mcMMOPlayer, delayedChorusBlocks); + + //Large delay because the tree takes a while to break + delayedHerbalismXPCheckTask.runTaskLater(mcMMO.p, 20); //Calculate Chorus XP + Bonus Drops 1 tick later + } + } + + public void checkDoubleDropsOnBrokenPlants(Collection brokenPlants) { + for(Block brokenPlant : brokenPlants) { + BlockState brokenPlantState = brokenPlant.getState(); + BlockData plantData = brokenPlantState.getBlockData(); + + //Check for double drops + if(!mcMMO.getPlaceStore().isTrue(brokenPlant)) { + + /* + * + * Natural Blocks + * + * + * + */ + + //Not all things that are natural should give double drops, make sure its fully mature as well + if(plantData instanceof Ageable) { + Ageable ageable = (Ageable) plantData; + + if(isAgeableMature(ageable) || isBizarreAgeable(plantData)) { + markForBonusDrops(brokenPlantState); + } + } else if(checkDoubleDrop(brokenPlantState)) { + //Add metadata to mark this block for double or triple drops + markForBonusDrops(brokenPlantState); + } + } else { + + /* + * + * Unnatural Blocks + * + */ + + //If its a Crop we need to reward XP when its fully grown + if(isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { + //Add metadata to mark this block for double or triple drops + markForBonusDrops(brokenPlantState); + } + } + } + } + + /** + * Checks if BlockData is ageable and we can trust that age for Herbalism rewards/XP reasons + * @param blockData target BlockData + * @return returns true if the ageable is trustworthy for Herbalism XP / Rewards + */ + public boolean isBizarreAgeable(BlockData blockData) { + if(blockData instanceof Ageable) { + //Catcus and Sugar Canes cannot be trusted + switch(blockData.getMaterial()) { + case CACTUS: + case SUGAR_CANE: + return true; + default: + return false; + } + } + + return false; + } + + public void markForBonusDrops(BlockState brokenPlantState) { + //Add metadata to mark this block for double or triple drops + boolean awardTriple = mcMMOPlayer.getAbilityMode(SuperAbilityType.GREEN_TERRA); + BlockUtils.markDropsAsBonus(brokenPlantState, awardTriple); + } + + /** + * Checks if a block is an ageable and if that ageable is fully mature + * @param plantData target plant + * @return returns true if the block is both an ageable and fully mature + */ + public boolean isAgeableAndFullyMature(BlockData plantData) { + return plantData instanceof Ageable && isAgeableMature((Ageable) plantData); + } + + public void awardXPForPlantBlocks(HashSet brokenPlants) { + int xpToReward = 0; + + for(Block brokenPlantBlock : brokenPlants) { + BlockState brokenBlockNewState = brokenPlantBlock.getState(); + BlockData plantData = brokenBlockNewState.getBlockData(); + + if(mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) { + /* + * + * Unnatural Blocks + * + * + */ + + //If its a Crop we need to reward XP when its fully grown + if(isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { + xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + } + + //Mark it as natural again as it is being broken + mcMMO.getPlaceStore().setFalse(brokenBlockNewState); + } else { + /* + * + * Natural Blocks + * + * + */ + + //Calculate XP + if(plantData instanceof Ageable) { + Ageable plantAgeable = (Ageable) plantData; + if(isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { + xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + } + } else { + xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType()); + } + } + } + + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Plants processed: "+brokenPlants.size()); + } + + //Reward XP + if(xpToReward > 0) { + applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + } + } + + public boolean isAgeableMature(Ageable ageable) { + return ageable.getAge() == ageable.getMaximumAge() + && ageable.getAge() != 0; + } + + /** + * Award XP for any blocks that used to be something else but are now AIR + * @param brokenPlants snapshot of broken blocks + */ + public void awardXPForBlockSnapshots(ArrayList brokenPlants) { + /* + * This handles XP for blocks that we need to check are broken after the fact + * This only applies to chorus trees right now + */ + int xpToReward = 0; + int blocksGivingXP = 0; + + for(BlockSnapshot blockSnapshot : brokenPlants) { + BlockState brokenBlockNewState = blockSnapshot.getBlockRef().getState(); + + //Remove metadata from the snapshot of blocks + if(brokenBlockNewState.hasMetadata(mcMMO.BONUS_DROPS_METAKEY)) { + brokenBlockNewState.removeMetadata(mcMMO.BONUS_DROPS_METAKEY, mcMMO.p); + } + + //If the block is not AIR that means it wasn't broken + if(brokenBlockNewState.getType() != Material.AIR) { + continue; + } + + if(mcMMO.getPlaceStore().isTrue(brokenBlockNewState)) { + //Mark it as natural again as it is being broken + mcMMO.getPlaceStore().setFalse(brokenBlockNewState); + } else { + //TODO: Do we care about chorus flower age? + //Calculate XP for the old type + xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, blockSnapshot.getOldType()); + blocksGivingXP++; + } + } + + if(mcMMOPlayer.isDebugMode()) { + mcMMOPlayer.getPlayer().sendMessage("Chorus Plants checked for XP: "+brokenPlants.size()); + mcMMOPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP); + } + + //Reward XP + if(xpToReward > 0) { + applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + } + } + + /** + * Process and return plant blocks from a BlockBreakEvent + * @param blockBreakEvent target event + * @return a set of plant-blocks that were broken as a result of this event + */ + private HashSet getBrokenHerbalismBlocks(BlockBreakEvent blockBreakEvent) { + //Get an updated capture of this block + BlockState originalBlockBlockState = blockBreakEvent.getBlock().getState(); + Material originalBlockMaterial = originalBlockBlockState.getType(); + HashSet blocksBroken = new HashSet<>(); //Blocks broken + + //Check if this block is a one block plant or not + boolean oneBlockPlant = isOneBlockPlant(originalBlockMaterial); + + if(oneBlockPlant) { + //If the block is a one-block plant return only that + blocksBroken.add(originalBlockBlockState.getBlock()); + } else { + //If the block is a multi-block structure, capture a set of all blocks broken and return that + blocksBroken = getBrokenBlocksMultiBlockPlants(originalBlockBlockState, blockBreakEvent); + } + + //Return all broken plant-blocks + return blocksBroken; + } + + private HashSet getBrokenChorusBlocks(BlockState originalBreak) { + HashSet traversedBlocks = grabChorusTreeBrokenBlocksRecursive(originalBreak.getBlock(), new HashSet<>()); + return traversedBlocks; + } + + private HashSet grabChorusTreeBrokenBlocksRecursive(Block currentBlock, HashSet traversed) { + if (!isChorusTree(currentBlock.getType())) + return traversed; + + // Prevent any infinite loops, who needs more than 256 chorus anyways + if (traversed.size() > 256) + return traversed; + + if (!traversed.add(currentBlock)) + return traversed; + + //Grab all Blocks in the Tree + for (BlockFace blockFace : new BlockFace[] { BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST ,BlockFace.WEST}) + grabChorusTreeBrokenBlocksRecursive(currentBlock.getRelative(blockFace, 1), traversed); + + traversed.add(currentBlock); + + return traversed; + } + + /** + * Grab a set of all plant blocks that are broken as a result of this event + * The method to grab these blocks is a bit hacky and does not hook into the API + * Basically we expect the blocks to be broken if this event is not cancelled and we determine which block are broken on our end rather than any event state captures + * + * @param blockBreakEvent target event + * @return a set of plant-blocks broken from this event + */ + protected HashSet getBrokenBlocksMultiBlockPlants(BlockState originalBlockBroken, BlockBreakEvent blockBreakEvent) { + //Track the broken blocks + HashSet brokenBlocks; + + if (isChorusBranch(originalBlockBroken.getType())) { + brokenBlocks = getBrokenChorusBlocks(originalBlockBroken); + } else { + brokenBlocks = getBlocksBrokenAbove(originalBlockBroken); + } + + return brokenBlocks; + } + + private boolean isChorusBranch(Material blockType) { + return blockType == Material.CHORUS_PLANT; + } + + private boolean isChorusTree(Material blockType) { + return blockType == Material.CHORUS_PLANT || blockType == Material.CHORUS_FLOWER; + } + + /** + * Grabs blocks upwards from a target block + * A lot of Plants/Crops in Herbalism only break vertically from a broken block + * The vertical search returns early if it runs into anything that is not a multi-block plant + * Multi-block plants are hard-coded and kept in {@link MaterialMapStore} + * + * @param breakPointBlockState The point of the "break" + * @return A set of blocks above the target block which can be assumed to be broken + */ + private HashSet getBlocksBrokenAbove(BlockState breakPointBlockState) { + HashSet brokenBlocks = new HashSet<>(); + Block block = breakPointBlockState.getBlock(); + + //Add the initial block to the set + brokenBlocks.add(block); + + //Limit our search + int maxHeight = 255; + + // Search vertically for multi-block plants, exit early if any non-multi block plants + for (int y = 1; y < maxHeight; y++) { + //TODO: Should this grab state? It would be more expensive.. + Block relativeUpBlock = block.getRelative(BlockFace.UP, y); + + //Abandon our search if the block isn't multi + if(!mcMMO.getMaterialMapStore().isMultiBlockPlant(relativeUpBlock.getType())) + break; + + brokenBlocks.add(relativeUpBlock); + } + + return brokenBlocks; + } + + /** + * If the plant is considered a one block plant + * This is determined by seeing if it exists in a hard-coded collection of Multi-Block plants + * @param material target plant material + * @return true if the block is not contained in the collection of multi-block plants + */ + private boolean isOneBlockPlant(Material material) { + return !mcMMO.getMaterialMapStore().isMultiBlockPlant(material); } /** @@ -184,7 +524,7 @@ public class HerbalismManager extends SkillManager { * @param blockState target block state * @return true if double drop succeeds */ - public boolean checkDoubleDrop(BlockState blockState) + private boolean checkDoubleDrop(BlockState blockState) { return BlockUtils.checkDoubleDrops(getPlayer(), blockState, skill, SubSkillType.HERBALISM_DOUBLE_DROPS); } @@ -324,7 +664,7 @@ public class HerbalismManager extends SkillManager { return; } - if (!handleBlockState(blockState, greenTerra)) { + if (!processGrowingPlants(blockState, greenTerra)) { return; } @@ -341,7 +681,7 @@ public class HerbalismManager extends SkillManager { new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0); } - private boolean handleBlockState(BlockState blockState, boolean greenTerra) { + private boolean processGrowingPlants(BlockState blockState, boolean greenTerra) { int greenThumbStage = getGreenThumbStage(); blockState.setMetadata(mcMMO.greenThumbDataKey, new FixedMetadataValue(mcMMO.p, (int) (System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR))); diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 87eb8ddd3..ec01ea444 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -11,6 +11,7 @@ import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import org.bukkit.Material; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; @@ -261,8 +262,9 @@ public final class BlockUtils { public static boolean isFullyGrown(BlockState blockState) { BlockData data = blockState.getBlockData(); - if (data.getMaterial() == Material.CACTUS || data.getMaterial() == Material.SUGAR_CANE) + if (data.getMaterial() == Material.CACTUS || data.getMaterial() == Material.SUGAR_CANE) { return true; + } if (data instanceof Ageable) { Ageable ageable = (Ageable) data; return ageable.getAge() == ageable.getMaximumAge(); diff --git a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java index c46c2e66e..9ae5d9cf7 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java @@ -20,7 +20,7 @@ public class MaterialMapStore { private HashSet herbalismAbilityBlackList; private HashSet blockCrackerWhiteList; private HashSet canMakeShroomyWhiteList; - private HashSet multiBlockEntities; + private HashSet multiBlockPlant; private HashSet foodItemWhiteList; public MaterialMapStore() @@ -32,15 +32,15 @@ public class MaterialMapStore { herbalismAbilityBlackList = new HashSet<>(); blockCrackerWhiteList = new HashSet<>(); canMakeShroomyWhiteList = new HashSet<>(); - multiBlockEntities = new HashSet<>(); + multiBlockPlant = new HashSet<>(); foodItemWhiteList = new HashSet<>(); fillHardcodedHashSets(); } - public boolean isMultiBlock(Material material) + public boolean isMultiBlockPlant(Material material) { - return multiBlockEntities.contains(material.getKey().getKey()); + return multiBlockPlant.contains(material.getKey().getKey()); } public boolean isAbilityActivationBlackListed(Material material) @@ -81,13 +81,13 @@ public class MaterialMapStore { private void fillHardcodedHashSets() { fillAbilityBlackList(); - filltoolBlackList(); + fillToolBlackList(); fillMossyWhiteList(); fillLeavesWhiteList(); fillHerbalismAbilityBlackList(); fillBlockCrackerWhiteList(); fillShroomyWhiteList(); - fillMultiBlockEntitiesList(); + fillMultiBlockPlantSet(); fillFoodWhiteList(); } @@ -134,16 +134,30 @@ public class MaterialMapStore { return foodItemWhiteList.contains(material.getKey().getKey()); } - private void fillMultiBlockEntitiesList() + private void fillMultiBlockPlantSet() { - multiBlockEntities.add("cactus"); - multiBlockEntities.add("chorus_plant"); - multiBlockEntities.add("sugar_cane"); - multiBlockEntities.add("kelp_plant"); - multiBlockEntities.add("kelp"); - multiBlockEntities.add("tall_seagrass"); - multiBlockEntities.add("tall_grass"); - multiBlockEntities.add("bamboo"); + //Single Block Plants +// plantBlockSet.add("melon"); +// plantBlockSet.add("pumpkin"); +// plantBlockSet.add("potatoes"); +// plantBlockSet.add("carrots"); +// plantBlockSet.add("beetroots"); +// plantBlockSet.add("nether_wart"); +// plantBlockSet.add("grass"); +// plantBlockSet.add("fern"); +// plantBlockSet.add("large_fern"); + + //Multi-Block Plants + multiBlockPlant.add("cactus"); + multiBlockPlant.add("chorus_plant"); + multiBlockPlant.add("chorus_flower"); + multiBlockPlant.add("sugar_cane"); + multiBlockPlant.add("kelp_plant"); + multiBlockPlant.add("kelp"); + multiBlockPlant.add("tall_seagrass"); + multiBlockPlant.add("large_fern"); + multiBlockPlant.add("tall_grass"); + multiBlockPlant.add("bamboo"); } private void fillShroomyWhiteList() @@ -287,7 +301,7 @@ public class MaterialMapStore { abilityBlackList.add("sign"); //1.13 and lower? } - private void filltoolBlackList() + private void fillToolBlackList() { //TODO: Add anvils / missing logs toolBlackList.add("black_bed"); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 675d1a811..5f5aa4ce3 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -426,6 +426,8 @@ Skills: ### Bonus_Drops: Herbalism: + Chorus_Fruit: true + Chorus_Plant: true Beetroots: true Beetroot: true Brown_Mushroom: true diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 01be9f9f1..f8e67156a 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -311,26 +311,25 @@ Experience_Values: Dead_Horn_Coral_Wall_Fan: 10 Allium: 300 Azure_Bluet: 150 - Beetroots_Ripe: 50 Blue_Orchid: 150 Brown_Mushroom: 150 Cactus: 30 - Carrots_Ripe: 50 - Chorus_Flower_Ripe: 25 Chorus_Flower: 25 Chorus_Plant: 1 - Cocoa_Ripe: 30 - Wheat_Ripe: 50 + Carrots: 50 + Cocoa: 30 + Potatoes: 50 + Wheat: 50 + Beetroots: 50 + Nether_Wart: 50 Dead_Bush: 30 Lilac: 50 Melon: 20 - Nether_Wart_Ripe: 50 Orange_Tulip: 150 Oxeye_Daisy: 150 Peony: 50 Pink_Tulip: 150 Poppy: 100 - Potatoes_Ripe: 50 Pumpkin: 20 Red_Mushroom: 150 Red_Tulip: 150 @@ -347,8 +346,8 @@ Experience_Values: Dandelion: 100 Bamboo: 10 Cornflower: 150 - Lily_of_the_valley: 150 - Wither_rose: 500 + Lily_Of_The_Valley: 150 + Wither_Rose: 500 Mining: Magma_Block: 30 Tube_Coral_Block: 75 From 67a687ee4035b12ab2f7c9fc95783b65bfb27a9d Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 01:55:23 -0700 Subject: [PATCH 22/31] Fix Ender Pearls not preventing XP gains in offhand --- Changelog.txt | 9 ++++++--- pom.xml | 2 +- .../datatypes/skills/subskills/acrobatics/Roll.java | 3 ++- .../java/com/gmail/nossr50/listeners/EntityListener.java | 5 ++--- src/main/java/com/gmail/nossr50/util/BlockUtils.java | 1 - src/main/java/com/gmail/nossr50/util/ItemUtils.java | 5 +++++ 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 45966f184..999d37e29 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,17 +1,20 @@ Version 2.1.95 Added missing Chorus_Fruit & Chorus_Plant entries to Herbalism's Bonus Drops in config.yml (See notes) - Added 'Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart' to Herbalism in experience.yml (See notes) Fixed a bug preventing Wandering Traders from granting XP Fixed a bug that prevented Chorus Tree's from giving full XP if you broke anything other than the bottom block Fixed a bug which could cause Large Fern's to reward less XP Fixed a bug where certain herbalism crops could have fewer than intended bonus drops - Added missing 'Chorus_Flower' entry to herbalism in experience.yml (update your config manually or delete the file to regenerate it) + Fixed a bug involving Ender Pearl and Acrobatics + Added 'Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart' to Herbalism in experience.yml (See notes) + Removed the _Ripe entries from experience.yml (no longer used) + Added missing 'Chorus_Flower' entry to herbalism in experience.yml Added some debug messages about XP gains if you are in debug mode Added some debug messages for Acrobatics if you are in debug mode + Added some debug messages for Herbalism if you are in debug mode NOTES: Add 'Chorus_Fruit' and 'Chorus_Plant' under Bonus_Drops.Herbalism in config.yml or you will not be getting double drops for Chorus Fruit. - You shouldn't need to add "Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart" to your experience file, it seems that file updates automatically for missing entries. + You shouldn't need to add "Chorus_Flower, Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart" to your experience file, it seems that config file updates automatically for missing entries. Version 2.1.94 2 new devs have joined the mcMMO team (electronicboy, kashike), bringing the active dev team to 3 including myself! Strings relating to authors of mcMMO have been updated to reflect this diff --git a/pom.xml b/pom.xml index b19bd57e9..f21720654 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.95-SNAPSHOT + 2.1.95 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 78534523f..2f9a76f95 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; @@ -276,7 +277,7 @@ public class Roll extends AcrobaticsSubSkill { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); - if (player.getInventory().getItemInMainHand().getType() == Material.ENDER_PEARL || player.isInsideVehicle()) { + if (ItemUtils.hasItemInEitherHand(player, Material.ENDER_PEARL) || player.isInsideVehicle()) { if(mcMMOPlayer.isDebugMode()) { mcMMOPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle"); } diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index ec004949a..101b5868d 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -72,8 +72,6 @@ public class EntityListener implements Listener { if(!ExperienceConfig.getInstance().isEndermanEndermiteFarmingPrevented()) return; - if(event.getReason() == EntityTargetEvent.TargetReason.TEMPT) - //It's rare but targets can be null sometimes if(event.getTarget() == null) { @@ -83,7 +81,7 @@ public class EntityListener implements Listener { //Prevent entities from giving XP if they target endermite if(event.getTarget() instanceof Endermite) { - if(event.getEntity().getMetadata(mcMMO.entityMetadataKey) == null || event.getEntity().getMetadata(mcMMO.entityMetadataKey).size() <= 0) + if(event.getEntity().hasMetadata(mcMMO.entityMetadataKey)) event.getEntity().setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue); } } @@ -189,6 +187,7 @@ public class EntityListener implements Listener { if (mcMMO.getPlaceStore().isTrue(block) && !isTracked) { mcMMO.getPlaceStore().setFalse(block); + entity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue); } else if (isTracked) { diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index ec01ea444..2d6b47343 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import org.bukkit.Material; -import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index ca1aff840..a635f3155 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.entity.Player; import org.bukkit.inventory.FurnaceRecipe; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; @@ -32,6 +33,10 @@ public final class ItemUtils { } } + public static boolean hasItemInEitherHand(Player player, Material material) { + return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material; + } + /** * Checks if the item is a sword. * From c818bf82b0983f60d125d3dabb9efdaf034b6d9f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 02:07:55 -0700 Subject: [PATCH 23/31] Cap how much XP can be given for Roll based on damage --- Changelog.txt | 1 + .../nossr50/datatypes/skills/subskills/acrobatics/Roll.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 999d37e29..850e9b9bd 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,6 +5,7 @@ Version 2.1.95 Fixed a bug which could cause Large Fern's to reward less XP Fixed a bug where certain herbalism crops could have fewer than intended bonus drops Fixed a bug involving Ender Pearl and Acrobatics + Added some protection to Acrobatics to prevent gaining too much XP in one Roll. Added 'Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart' to Herbalism in experience.yml (See notes) Removed the _Ripe entries from experience.yml (no longer used) Added missing 'Chorus_Flower' entry to herbalism in experience.yml diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 2f9a76f95..5e28dd901 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -297,6 +297,9 @@ public class Roll extends AcrobaticsSubSkill { } private float calculateRollXP(Player player, double damage, boolean isRoll) { + //Clamp Damage to account for insane DRs + damage = Math.min(40, damage); + ItemStack boots = player.getInventory().getBoots(); float xp = (float) (damage * (isRoll ? ExperienceConfig.getInstance().getRollXPModifier() : ExperienceConfig.getInstance().getFallXPModifier())); From 6c58e8a2433e7b78f74ad445e70f4f8723c7a121 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 02:33:39 -0700 Subject: [PATCH 24/31] Limit Break Nerfs --- Changelog.txt | 4 + .../nossr50/util/skills/CombatUtils.java | 76 ++++++++++++++++--- .../resources/locale/locale_en_US.properties | 16 ++-- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 850e9b9bd..baa58431f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,8 @@ Version 2.1.95 Added missing Chorus_Fruit & Chorus_Plant entries to Herbalism's Bonus Drops in config.yml (See notes) + Limit Break damage bonuses now only apply to Players + Limit Break now does dramatically less damage to players with lower grades of armor + Updated in game text to reflect changes to Limit Break Fixed a bug preventing Wandering Traders from granting XP Fixed a bug that prevented Chorus Tree's from giving full XP if you broke anything other than the bottom block Fixed a bug which could cause Large Fern's to reward less XP @@ -8,6 +11,7 @@ Version 2.1.95 Added some protection to Acrobatics to prevent gaining too much XP in one Roll. Added 'Carrots, Cocoa, Potatoes, Wheat, Beetroots, Nether_Wart' to Herbalism in experience.yml (See notes) Removed the _Ripe entries from experience.yml (no longer used) + Updated locale string 'Swords.SubSkill.SwordsLimitBreak.Description' & 'Swords.SubSkill.SwordsLimitBreak.Stat' Added missing 'Chorus_Flower' entry to herbalism in experience.yml Added some debug messages about XP gains if you are in debug mode Added some debug messages for Acrobatics if you are in debug mode diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 598310e41..39cdc50d0 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -24,6 +24,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableMap; import org.bukkit.GameMode; import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; @@ -74,7 +75,7 @@ public final class CombatUtils { swordsManager.serratedStrikes(target, initialDamage, modifiers); } - if(canUseLimitBreak(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) + if(canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { finalDamage+=getLimitBreakDamage(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK); } @@ -118,7 +119,7 @@ public final class CombatUtils { finalDamage+=axesManager.criticalHit(target, finalDamage); } - if(canUseLimitBreak(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) + if(canUseLimitBreak(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK)) { finalDamage+=getLimitBreakDamage(player, SubSkillType.AXES_AXES_LIMIT_BREAK); } @@ -157,7 +158,7 @@ public final class CombatUtils { unarmedManager.disarmCheck((Player) target); } - if(canUseLimitBreak(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) + if(canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { finalDamage+=getLimitBreakDamage(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK); } @@ -225,7 +226,7 @@ public final class CombatUtils { archeryManager.retrieveArrows(target, arrow); } - if(canUseLimitBreak(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) + if(canUseLimitBreak(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { finalDamage+=getLimitBreakDamage(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); } @@ -383,8 +384,61 @@ public final class CombatUtils { } } - public static int getLimitBreakDamage(Player player, SubSkillType subSkillType) { - return RankUtils.getRank(player, subSkillType); + public static int getLimitBreakDamage(Player player, Player defender, SubSkillType subSkillType) { + int rawDamageBoost = RankUtils.getRank(player, subSkillType); + int armorQualityLevel = getArmorQualityLevel(defender); + + if(armorQualityLevel <= 4) { + rawDamageBoost *= .25; //75% Nerf + } else if(armorQualityLevel <= 8) { + rawDamageBoost *= .50; //50% Nerf + } else if(armorQualityLevel <= 12) { + rawDamageBoost *= .75; //25% Nerf + } + + return rawDamageBoost; + } + + public static int getArmorQualityLevel(Player defender) { + int armorQualityLevel = 0; + + for(ItemStack itemStack : defender.getInventory().getArmorContents()) { + if(itemStack != null) { + armorQualityLevel += getArmorQuality(itemStack); + } + } + + return armorQualityLevel; + } + + private static int getArmorQuality(ItemStack itemStack) { + int quality = 0; + + switch(itemStack.getType()) { + case LEATHER_HELMET: + case LEATHER_BOOTS: + case LEATHER_CHESTPLATE: + case LEATHER_LEGGINGS: + return 1; + case IRON_HELMET: + case IRON_BOOTS: + case IRON_CHESTPLATE: + case IRON_LEGGINGS: + return 2; + case GOLDEN_HELMET: + case GOLDEN_BOOTS: + case GOLDEN_CHESTPLATE: + case GOLDEN_LEGGINGS: + return 3; + case DIAMOND_HELMET: + case DIAMOND_BOOTS: + case DIAMOND_CHESTPLATE: + case DIAMOND_LEGGINGS: + return 6; + default: + return 1; + + } } /** @@ -392,9 +446,13 @@ public final class CombatUtils { * @param player target player * @return true if the player has access to the limit break */ - public static boolean canUseLimitBreak(Player player, SubSkillType subSkillType) { - return RankUtils.hasUnlockedSubskill(player, subSkillType) - && Permissions.isSubSkillEnabled(player, subSkillType); + public static boolean canUseLimitBreak(Player player, LivingEntity target, SubSkillType subSkillType) { + if(target instanceof Player) { + return RankUtils.hasUnlockedSubskill(player, subSkillType) + && Permissions.isSubSkillEnabled(player, subSkillType); + } else { + return false; + } } /** diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 5c2e100c4..36c5cc62a 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -171,8 +171,8 @@ Archery.SubSkill.ArrowRetrieval.Name=Arrow Retrieval Archery.SubSkill.ArrowRetrieval.Description=Chance to retrieve arrows from corpses Archery.SubSkill.ArrowRetrieval.Stat=Arrow Recovery Chance Archery.SubSkill.ArcheryLimitBreak.Name=Archery Limit Break -Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. -Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Bonus DMG +Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. (PVP Only) +Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break PVP DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY #AXES @@ -198,8 +198,8 @@ Axes.SubSkill.CriticalStrikes.Stat=Critical Strike Chance Axes.SubSkill.AxeMastery.Name=Axe Mastery Axes.SubSkill.AxeMastery.Description=Adds bonus DMG Axes.SubSkill.AxesLimitBreak.Name=Axes Limit Break -Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. -Axes.SubSkill.AxesLimitBreak.Stat=Limit Break Bonus DMG +Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. (PVP Only) +Axes.SubSkill.AxesLimitBreak.Stat=Limit Break PVP DMG Axes.SubSkill.ArmorImpact.Name=Armor Impact Axes.SubSkill.ArmorImpact.Description=Strike with enough force to shatter armor Axes.SubSkill.GreaterImpact.Name=Greater Impact @@ -423,8 +423,8 @@ Swords.SubSkill.Stab.Name=Stab Swords.SubSkill.Stab.Description=Adds bonus damage to your attacks. Swords.SubSkill.Stab.Stat=Stab Damage Swords.SubSkill.SwordsLimitBreak.Name=Swords Limit Break -Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. -Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break Bonus DMG +Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. (PVP Only) +Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break PVP DMG Swords.SubSkill.Rupture.Stat=Rupture Chance Swords.SubSkill.Rupture.Stat.Extra=Rupture: [[GREEN]]{0} ticks [{1} DMG vs Player] [{2} DMG vs Mobs] Swords.Effect.4=Serrated Strikes Rupture+ @@ -502,8 +502,8 @@ Unarmed.SubSkill.Disarm.Name=Disarm Unarmed.SubSkill.Disarm.Description=Drops the foes item held in hand Unarmed.SubSkill.Disarm.Stat=Disarm Chance Unarmed.SubSkill.UnarmedLimitBreak.Name=Unarmed Limit Break -Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. -Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break Bonus DMG +Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. (PVP Only) +Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break PVP DMG Unarmed.SubSkill.IronArmStyle.Name=Iron Arm Style Unarmed.SubSkill.IronArmStyle.Description=Hardens your arm over time Unarmed.SubSkill.ArrowDeflect.Name=Arrow Deflect From 6bc57f184ad89735eb698a8e4c8c9ab60627e96d Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 02:48:17 -0700 Subject: [PATCH 25/31] 2.1.95 --- Changelog.txt | 3 ++- .../nossr50/commands/skills/ArcheryCommand.java | 2 +- .../nossr50/commands/skills/AxesCommand.java | 2 +- .../nossr50/commands/skills/SwordsCommand.java | 2 +- .../nossr50/commands/skills/UnarmedCommand.java | 2 +- .../nossr50/skills/unarmed/UnarmedManager.java | 5 +++-- .../gmail/nossr50/util/skills/CombatUtils.java | 14 ++++++++------ .../resources/locale/locale_en_US.properties | 16 ++++++++-------- 8 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index baa58431f..7b392b3e8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,8 +1,9 @@ Version 2.1.95 Added missing Chorus_Fruit & Chorus_Plant entries to Herbalism's Bonus Drops in config.yml (See notes) - Limit Break damage bonuses now only apply to Players Limit Break now does dramatically less damage to players with lower grades of armor + Limit Break damage bonuses now only apply to Players Updated in game text to reflect changes to Limit Break + Fixed a bug where opponents used your stats instead of their own to activate Iron Grip Fixed a bug preventing Wandering Traders from granting XP Fixed a bug that prevented Chorus Tree's from giving full XP if you broke anything other than the bottom block Fixed a bug which could cause Large Fern's to reward less XP diff --git a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java index 5b9359da7..42f4510f4 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/ArcheryCommand.java @@ -77,7 +77,7 @@ public class ArcheryCommand extends SkillCommand { if(canUseSubskill(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java index 857b07f03..1ca55780a 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java @@ -98,7 +98,7 @@ public class AxesCommand extends SkillCommand { if(canUseSubskill(player, SubSkillType.AXES_AXES_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.AXES_AXES_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.AXES_AXES_LIMIT_BREAK)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.AXES_AXES_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 3b46b7b9a..0bdeaba9c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -103,7 +103,7 @@ public class SwordsCommand extends SkillCommand { if(canUseSubskill(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java index 64952dca4..e126cf38c 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java @@ -116,7 +116,7 @@ public class UnarmedCommand extends SkillCommand { if(canUseSubskill(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { messages.add(getStatMessage(SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, - String.valueOf(CombatUtils.getLimitBreakDamage(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)))); + String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, 1000)))); } return messages; diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 4df9d7903..78bef306a 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -181,8 +181,9 @@ public class UnarmedManager extends SkillManager { * @return true if the defender was not disarmed, false otherwise */ private boolean hasIronGrip(Player defender) { - if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) - && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, getPlayer())) { + if (!Misc.isNPCEntityExcludingVillagers(defender) + && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) + && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, defender)) { NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Defender"); NotificationManager.sendPlayerInformation(getPlayer(), NotificationType.SUBSKILL_MESSAGE, "Unarmed.Ability.IronGrip.Attacker"); diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 39cdc50d0..636289935 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -24,7 +24,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableMap; import org.bukkit.GameMode; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; @@ -77,7 +76,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK); } applyScaledModifiers(initialDamage, finalDamage, event); @@ -121,7 +120,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, SubSkillType.AXES_AXES_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.AXES_AXES_LIMIT_BREAK); } applyScaledModifiers(initialDamage, finalDamage, event); @@ -160,7 +159,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK); } } @@ -228,7 +227,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); } double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow); @@ -385,8 +384,11 @@ public final class CombatUtils { } public static int getLimitBreakDamage(Player player, Player defender, SubSkillType subSkillType) { + return getLimitBreakDamageAgainstQuality(player, subSkillType, getArmorQualityLevel(defender)); + } + + public static int getLimitBreakDamageAgainstQuality(Player player, SubSkillType subSkillType, int armorQualityLevel) { int rawDamageBoost = RankUtils.getRank(player, subSkillType); - int armorQualityLevel = getArmorQualityLevel(defender); if(armorQualityLevel <= 4) { rawDamageBoost *= .25; //75% Nerf diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 36c5cc62a..e269a8007 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -171,8 +171,8 @@ Archery.SubSkill.ArrowRetrieval.Name=Arrow Retrieval Archery.SubSkill.ArrowRetrieval.Description=Chance to retrieve arrows from corpses Archery.SubSkill.ArrowRetrieval.Stat=Arrow Recovery Chance Archery.SubSkill.ArcheryLimitBreak.Name=Archery Limit Break -Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. (PVP Only) -Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break PVP DMG +Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) +Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break PVP Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY #AXES @@ -198,8 +198,8 @@ Axes.SubSkill.CriticalStrikes.Stat=Critical Strike Chance Axes.SubSkill.AxeMastery.Name=Axe Mastery Axes.SubSkill.AxeMastery.Description=Adds bonus DMG Axes.SubSkill.AxesLimitBreak.Name=Axes Limit Break -Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. (PVP Only) -Axes.SubSkill.AxesLimitBreak.Stat=Limit Break PVP DMG +Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) +Axes.SubSkill.AxesLimitBreak.Stat=Limit Break PVP Max DMG Axes.SubSkill.ArmorImpact.Name=Armor Impact Axes.SubSkill.ArmorImpact.Description=Strike with enough force to shatter armor Axes.SubSkill.GreaterImpact.Name=Greater Impact @@ -423,8 +423,8 @@ Swords.SubSkill.Stab.Name=Stab Swords.SubSkill.Stab.Description=Adds bonus damage to your attacks. Swords.SubSkill.Stab.Stat=Stab Damage Swords.SubSkill.SwordsLimitBreak.Name=Swords Limit Break -Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. (PVP Only) -Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break PVP DMG +Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) +Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break PVP Max DMG Swords.SubSkill.Rupture.Stat=Rupture Chance Swords.SubSkill.Rupture.Stat.Extra=Rupture: [[GREEN]]{0} ticks [{1} DMG vs Player] [{2} DMG vs Mobs] Swords.Effect.4=Serrated Strikes Rupture+ @@ -502,8 +502,8 @@ Unarmed.SubSkill.Disarm.Name=Disarm Unarmed.SubSkill.Disarm.Description=Drops the foes item held in hand Unarmed.SubSkill.Disarm.Stat=Disarm Chance Unarmed.SubSkill.UnarmedLimitBreak.Name=Unarmed Limit Break -Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. (PVP Only) -Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break PVP DMG +Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) +Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break PVP Max DMG Unarmed.SubSkill.IronArmStyle.Name=Iron Arm Style Unarmed.SubSkill.IronArmStyle.Description=Hardens your arm over time Unarmed.SubSkill.ArrowDeflect.Name=Arrow Deflect From 03fd558e1b3e4da3eff033d327f4fef50805fcca Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 06:11:15 -0700 Subject: [PATCH 26/31] Add toggle to allow piston cheating --- .../gmail/nossr50/config/experience/ExperienceConfig.java | 1 + .../java/com/gmail/nossr50/listeners/BlockListener.java | 8 ++++++++ src/main/resources/experience.yml | 1 + 3 files changed, 10 insertions(+) diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index a6f6ef26c..13c88d329 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -145,6 +145,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader { /* EXPLOIT TOGGLES */ public boolean isEndermanEndermiteFarmingPrevented() { return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true); } + public boolean isPistonCheatingPrevented() { return config.getBoolean("ExploitFix.PistonCheating", true); } public boolean isPistonExploitPrevented() { return config.getBoolean("ExploitFix.Pistons", false); } public boolean allowUnsafeEnchantments() { return config.getBoolean("ExploitFix.UnsafeEnchantments", false); } public boolean isCOTWBreedingPrevented() { return config.getBoolean("ExploitFix.COTWBreeding", true); } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 1f43bbfbe..cd9cc12fd 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -129,6 +129,10 @@ public class BlockListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) return; + if(!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { + return; + } + BlockFace direction = event.getDirection(); Block movedBlock = event.getBlock(); movedBlock = movedBlock.getRelative(direction, 2); @@ -152,6 +156,10 @@ public class BlockListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) return; + if(!ExperienceConfig.getInstance().isPistonCheatingPrevented()) { + return; + } + // Get opposite direction so we get correct block BlockFace direction = event.getDirection(); Block movedBlock = event.getBlock().getRelative(direction); diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index f8e67156a..8df3dec66 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -33,6 +33,7 @@ ExploitFix: Acrobatics: true LavaStoneAndCobbleFarming: true TreeFellerReducedXP: true + PistonCheating: true Experience_Bars: # Turn this to false if you wanna disable XP bars Enable: true From cd0ed4b3858da8e396379268c62e678e5c31d5ca Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Jul 2019 06:13:33 -0700 Subject: [PATCH 27/31] Dev mode --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f21720654..fe53d7384 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.95 + 2.1.96-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO From 732e29f0a5c9eadce211b23a8895bc0b6eba6292 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Jul 2019 03:53:00 -0700 Subject: [PATCH 28/31] Add missing 's' to Nether_Bricks --- Changelog.txt | 10 ++++++++++ src/main/resources/experience.yml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 7b392b3e8..78edc7283 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,13 @@ +Version 2.1.96 + Added the setting 'ExploitFix.PistonCheating' to experience.yml at the request of a user + Added a missing 's' to Nether_Bricks (thanks Sikatsu) in experience.yml + + NOTES: + You shouldn't need to update you config entry for Nether_Bricks, I believe that file updates automatically (the old config system is a bit janky, some stuff updates, some other stuff doesn't.) + PistonCheating prevents blocks from being marked "natural" once they've been moved, we've never had an option for this before. + A discord user requested it, its a strange request but I added it anyways. + Of course, it defaults to "true" which prevents cheating with pistons. + Version 2.1.95 Added missing Chorus_Fruit & Chorus_Plant entries to Herbalism's Bonus Drops in config.yml (See notes) Limit Break now does dramatically less damage to players with lower grades of armor diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 8df3dec66..b4eab61d9 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -360,7 +360,7 @@ Experience_Values: Diamond_Ore: 2400 Emerald_Ore: 1000 End_Bricks: 50 - Nether_Brick: 50 + Nether_Bricks: 50 End_Stone: 15 Glowstone: 15 Gold_Ore: 1300 From 36932e397de116e307e45c6cf397a2295c0c38cf Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 8 Jul 2019 07:57:07 -0700 Subject: [PATCH 29/31] 2.1.96 --- Changelog.txt | 4 ++++ pom.xml | 2 +- .../nossr50/commands/skills/SkillCommand.java | 8 +++++++ .../gmail/nossr50/config/AdvancedConfig.java | 2 ++ .../nossr50/util/skills/CombatUtils.java | 22 ++++++++++++------- src/main/resources/advanced.yml | 2 ++ .../resources/locale/locale_en_US.properties | 18 +++++++-------- 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 78edc7283..3e246c26d 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,8 +1,12 @@ Version 2.1.96 + Added the setting 'Skills.General.LimitBreak.AllowPVE' to advanced.yml to allow Limit Break damage bonus to apply in PVE again, defaults to false + Updated Limit Break locale strings + Fixed a few more places where 'Archaeology' was misspelled in the locale Added the setting 'ExploitFix.PistonCheating' to experience.yml at the request of a user Added a missing 's' to Nether_Bricks (thanks Sikatsu) in experience.yml NOTES: + The Skill Tooltips are a bit limited right now, in the future they will be more flexible. In order to reflect that Limit Break doesn't always work in PVE (now up to server settings) I added a crappy note to its hover window tip. I'll be fixing this in the future. You shouldn't need to update you config entry for Nether_Bricks, I believe that file updates automatically (the old config system is a bit janky, some stuff updates, some other stuff doesn't.) PistonCheating prevents blocks from being marked "natural" once they've been moved, we've never had an option for this before. A discord user requested it, its a strange request but I added it anyways. diff --git a/pom.xml b/pom.xml index fe53d7384..c4f3466af 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.96-SNAPSHOT + 2.1.96 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 2fbea687a..6b4b1c19f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -274,6 +274,14 @@ public abstract class SkillCommand implements TabExecutor { } } + protected String getLimitBreakDescriptionParameter() { + if(AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { + return "(PVP/PVE)"; + } else { + return "(PVP)"; + } + } + protected abstract void dataCalculations(Player player, float skillValue); protected abstract void permissionsCheck(Player player); diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index fe9a9f46f..dccd1a4c8 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -636,6 +636,8 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { protected void loadKeys() {} /* GENERAL */ + + public boolean canApplyLimitBreakPVE() { return config.getBoolean("Skills.General.LimitBreak.AllowPVE", false); } public int getStartingLevel() { return config.getInt("Skills.General.StartingLevel", 1); } public boolean allowPlayerTips() { diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 636289935..1ee0cff4b 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.util.skills; +import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -76,7 +77,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, target, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK); } applyScaledModifiers(initialDamage, finalDamage, event); @@ -120,7 +121,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.AXES_AXES_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, target, SubSkillType.AXES_AXES_LIMIT_BREAK); } applyScaledModifiers(initialDamage, finalDamage, event); @@ -159,7 +160,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, target, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK); } } @@ -227,7 +228,7 @@ public final class CombatUtils { if(canUseLimitBreak(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK)) { - finalDamage+=getLimitBreakDamage(player, (Player) target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); + finalDamage+=getLimitBreakDamage(player, target, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK); } double distanceMultiplier = archeryManager.distanceXpBonusMultiplier(target, arrow); @@ -383,8 +384,13 @@ public final class CombatUtils { } } - public static int getLimitBreakDamage(Player player, Player defender, SubSkillType subSkillType) { - return getLimitBreakDamageAgainstQuality(player, subSkillType, getArmorQualityLevel(defender)); + public static int getLimitBreakDamage(Player player, LivingEntity defender, SubSkillType subSkillType) { + if(defender instanceof Player) { + Player playerDefender = (Player) defender; + return getLimitBreakDamageAgainstQuality(player, subSkillType, getArmorQualityLevel(playerDefender)); + } else { + return getLimitBreakDamageAgainstQuality(player, subSkillType, 1000); + } } public static int getLimitBreakDamageAgainstQuality(Player player, SubSkillType subSkillType, int armorQualityLevel) { @@ -445,11 +451,11 @@ public final class CombatUtils { /** * Checks if player has access to their weapons limit break - * @param player target player + * @param player target entity * @return true if the player has access to the limit break */ public static boolean canUseLimitBreak(Player player, LivingEntity target, SubSkillType subSkillType) { - if(target instanceof Player) { + if(target instanceof Player || AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { return RankUtils.hasUnlockedSubskill(player, subSkillType) && Permissions.isSubSkillEnabled(player, subSkillType); } else { diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index b6c98834e..6648a3dc7 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -77,6 +77,8 @@ Feedback: SendCopyOfMessageToChat: true Skills: General: + LimitBreak: + AllowPVE: false StartingLevel: 0 Ability: Length: diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index e269a8007..a695e141e 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -171,8 +171,8 @@ Archery.SubSkill.ArrowRetrieval.Name=Arrow Retrieval Archery.SubSkill.ArrowRetrieval.Description=Chance to retrieve arrows from corpses Archery.SubSkill.ArrowRetrieval.Stat=Arrow Recovery Chance Archery.SubSkill.ArcheryLimitBreak.Name=Archery Limit Break -Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) -Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break PVP Max DMG +Archery.SubSkill.ArcheryLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Archery.SubSkill.ArcheryLimitBreak.Stat=Limit Break Max DMG Archery.Listener=Archery: Archery.SkillName=ARCHERY #AXES @@ -198,8 +198,8 @@ Axes.SubSkill.CriticalStrikes.Stat=Critical Strike Chance Axes.SubSkill.AxeMastery.Name=Axe Mastery Axes.SubSkill.AxeMastery.Description=Adds bonus DMG Axes.SubSkill.AxesLimitBreak.Name=Axes Limit Break -Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) -Axes.SubSkill.AxesLimitBreak.Stat=Limit Break PVP Max DMG +Axes.SubSkill.AxesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Axes.SubSkill.AxesLimitBreak.Stat=Limit Break Max DMG Axes.SubSkill.ArmorImpact.Name=Armor Impact Axes.SubSkill.ArmorImpact.Description=Strike with enough force to shatter armor Axes.SubSkill.GreaterImpact.Name=Greater Impact @@ -219,7 +219,7 @@ Excavation.SubSkill.GigaDrillBreaker.Description=3x Drop Rate, 3x EXP, +Speed Excavation.SubSkill.GigaDrillBreaker.Stat=Giga Drill Breaker Duration Excavation.SubSkill.Archaeology.Name=Archaeology Excavation.SubSkill.Archaeology.Description=Unearth the secrets of the land! High skill levels increase your odds of finding experience orbs when you find treasure! -Excavation.SubSkill.Archaeology.Stat=Archaelogy Experience Orb Chance +Excavation.SubSkill.Archaeology.Stat=Archaeology Experience Orb Chance Excavation.SubSkill.Archaeology.Stat.Extra=Archaeology Experience Orb Amount Excavation.Listener=Excavation: Excavation.SkillName=EXCAVATION @@ -423,8 +423,8 @@ Swords.SubSkill.Stab.Name=Stab Swords.SubSkill.Stab.Description=Adds bonus damage to your attacks. Swords.SubSkill.Stab.Stat=Stab Damage Swords.SubSkill.SwordsLimitBreak.Name=Swords Limit Break -Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) -Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break PVP Max DMG +Swords.SubSkill.SwordsLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Swords.SubSkill.SwordsLimitBreak.Stat=Limit Break Max DMG Swords.SubSkill.Rupture.Stat=Rupture Chance Swords.SubSkill.Rupture.Stat.Extra=Rupture: [[GREEN]]{0} ticks [{1} DMG vs Player] [{2} DMG vs Mobs] Swords.Effect.4=Serrated Strikes Rupture+ @@ -502,8 +502,8 @@ Unarmed.SubSkill.Disarm.Name=Disarm Unarmed.SubSkill.Disarm.Description=Drops the foes item held in hand Unarmed.SubSkill.Disarm.Stat=Disarm Chance Unarmed.SubSkill.UnarmedLimitBreak.Name=Unarmed Limit Break -Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. (PVP Only) -Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break PVP Max DMG +Unarmed.SubSkill.UnarmedLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether or not it will boost damage in PVE. +Unarmed.SubSkill.UnarmedLimitBreak.Stat=Limit Break Max DMG Unarmed.SubSkill.IronArmStyle.Name=Iron Arm Style Unarmed.SubSkill.IronArmStyle.Description=Hardens your arm over time Unarmed.SubSkill.ArrowDeflect.Name=Arrow Deflect From 5f7f6fc55a5fc45907014227aa51b7a4a3310400 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 10 Jul 2019 05:03:33 -0700 Subject: [PATCH 30/31] Fixed a NPE with taming. --- Changelog.txt | 3 ++ pom.xml | 2 +- .../nossr50/util/skills/CombatUtils.java | 41 +++++++++++-------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 3e246c26d..931ddd615 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.97 + Fixed a NPE that could occur if a pet participated in combat and its master's mcMMO data was not available + Version 2.1.96 Added the setting 'Skills.General.LimitBreak.AllowPVE' to advanced.yml to allow Limit Break damage bonus to apply in PVE again, defaults to false Updated Limit Break locale strings diff --git a/pom.xml b/pom.xml index c4f3466af..d4dddacc9 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.96 + 2.1.97-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 1ee0cff4b..b15917943 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -173,25 +173,34 @@ public final class CombatUtils { double initialDamage = event.getDamage(); double finalDamage = initialDamage; - McMMOPlayer mcMMOPlayer = UserManager.getPlayer(master); - TamingManager tamingManager = mcMMOPlayer.getTamingManager(); + if(master != null && !master.isOnline() && master.isValid()) { + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(master); - if (tamingManager.canUseFastFoodService()) { - tamingManager.fastFoodService(wolf, event.getDamage()); + //Make sure the profiles been loaded + if(mcMMOPlayer == null) { + return; + } + + TamingManager tamingManager = mcMMOPlayer.getTamingManager(); + + if (tamingManager.canUseFastFoodService()) { + tamingManager.fastFoodService(wolf, event.getDamage()); + } + + tamingManager.pummel(target, wolf); + + if (tamingManager.canUseSharpenedClaws()) { + finalDamage+=tamingManager.sharpenedClaws(); + } + + if (tamingManager.canUseGore()) { + finalDamage+=tamingManager.gore(target, initialDamage); + } + + applyScaledModifiers(initialDamage, finalDamage, event); + startGainXp(mcMMOPlayer, target, PrimarySkillType.TAMING); } - tamingManager.pummel(target, wolf); - - if (tamingManager.canUseSharpenedClaws()) { - finalDamage+=tamingManager.sharpenedClaws(); - } - - if (tamingManager.canUseGore()) { - finalDamage+=tamingManager.gore(target, initialDamage); - } - - applyScaledModifiers(initialDamage, finalDamage, event); - startGainXp(mcMMOPlayer, target, PrimarySkillType.TAMING); } private static void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Arrow arrow) { From 99f8f345293d6a8b5cf537c30835aa448cd4542e Mon Sep 17 00:00:00 2001 From: Werner Date: Thu, 11 Jul 2019 16:27:14 +0200 Subject: [PATCH 31/31] Update locale_de.properties --- src/main/resources/locale/locale_de.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/locale/locale_de.properties b/src/main/resources/locale/locale_de.properties index 5c63a73e3..0c11d2e20 100644 --- a/src/main/resources/locale/locale_de.properties +++ b/src/main/resources/locale/locale_de.properties @@ -270,7 +270,7 @@ Commands.XPGain.Excavation = Graben und Sch\u00E4tze finden Commands.XPGain.Fishing = Angeln (Ach was :o) Commands.XPGain.Herbalism = Ernten Commands.XPGain.Mining = Erze und Steine abbauen -Commands.XPGain.Overhaul = &6Erfahrungs Erhalt: &3{0} +Commands.XPGain.Overhaul = &6Erfahrungserhalt: &3{0} Commands.XPGain.Repair = Reparieren Commands.XPGain.Swords = Monster angreifen Commands.XPGain.Taming = Monster z\u00E4hmen, mit dem Wolf k\u00E4mpfen