diff --git a/Changelog.txt b/Changelog.txt index 94e7c3c1c..6cc58c899 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -59,7 +59,7 @@ Version 2.1.0 ! (Skills) Some skill level rank requirements have changed ! (Skills) Fixed an edge case bug where Blast Mining wouldn't inform the player that it was on cooldown ! (Skills) mcMMO skills will now be on a scale from 1-100 instead of 0-1000 (for existing mcMMO installs this is opt-in and off by default) - ! (Skills) Skill Super Powers (Tree Feller, etc...) will now require level 10+ to use + ! (Skills) Skill Super Powers are now unlockabled skills, unlocking at level 10 ! (Skills) Acrobatics' Roll exploit detection was tweaked to still allow for Roll to trigger even if it rewards no XP ! (Skills) Acrobatics' Roll & Gracefull Roll are now considered the same skill (both mechanics are still there) ! (Skills) Woodcutting's Double Drop subskill is now named Harvest Lumber @@ -92,7 +92,7 @@ Version 2.1.0 ! (API) SecondaryAbilityEvent is now SubSkillEvent ! (API) SubSkillType has had many helpful methods added to it ! (API) GREEN_THUMB_PLANT & GREEN_THUMB_BLOCK are replaced by GREEN_THUMB - ! (Code) Refactored some unreadable code relating to SecondaryAbility activation in SkillUtils + ! (Code) Refactored some unreadable code relating to SecondaryAbilityType activation in SkillUtils Version 2.0.0 = Fixed an interaction between Tree Feller and Stripped Wood diff --git a/src/main/java/com/gmail/nossr50/commands/skills/McMMOWebLinks.java b/src/main/java/com/gmail/nossr50/commands/skills/McMMOWebLinks.java index 7939accfb..a6918ac4d 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/McMMOWebLinks.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/McMMOWebLinks.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.json.McMMOUrl; +import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.StringUtils; public enum McMMOWebLinks { @@ -20,4 +21,25 @@ public enum McMMOWebLinks { { return StringUtils.getCapitalized(toString()); } + + public String getLocaleDescription() + { + switch (this) + { + case WEBSITE: + return LocaleLoader.getString( "JSON.URL.Website"); + case DISCORD: + return LocaleLoader.getString( "JSON.URL.Discord"); + case PATREON: + return LocaleLoader.getString( "JSON.URL.Patreon"); + case HELP_TRANSLATE: + return LocaleLoader.getString( "JSON.URL.Translation"); + case SPIGOT: + return LocaleLoader.getString("JSON.URL.Spigot"); + case WIKI: + return LocaleLoader.getString("JSON.URL.Wiki"); + default: + return ""; + } + } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index a81c61435..cdda8a9a5 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -22,6 +22,9 @@ public class MmoInfoCommand implements TabExecutor { @Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { + /* + * Only allow players to use this command + */ if(commandSender instanceof Player) { if(args.length < 1) @@ -33,8 +36,14 @@ public class MmoInfoCommand implements TabExecutor { if(args == null || args[0] == null) return false; - //Real skill - if(InteractionManager.getAbstractByName(args[0]) != null || PrimarySkillType.SUBSKILL_NAMES.contains(args[0])) + if(args[0].equalsIgnoreCase( "???")) + { + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header")); + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", "???")); + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); + player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mystery")); + return true; + } else if(InteractionManager.getAbstractByName(args[0]) != null || PrimarySkillType.SUBSKILL_NAMES.contains(args[0])) { displayInfo(player, args[0]); return true; @@ -42,8 +51,10 @@ public class MmoInfoCommand implements TabExecutor { //Not a real skill player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.NoMatch")); + return true; } } + return false; } @@ -59,8 +70,6 @@ public class MmoInfoCommand implements TabExecutor { private void displayInfo(Player player, String subSkillName) { - System.out.println("[mcMMO] Debug: Grabbing info for skill "+subSkillName); - //Check to see if the skill exists in the new system AbstractSubSkill abstractSubSkill = InteractionManager.getAbstractByName(subSkillName); if(abstractSubSkill != null) diff --git a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java index 6b3b75848..b87516508 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java @@ -174,7 +174,7 @@ public class TamingCommand extends SkillCommand { protected List getTextComponents(Player player) { List textComponents = new ArrayList<>(); - TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.TAMING); + TextComponentFactory.getSubSkillTextComponents(player, textComponents, this.skill); return textComponents; } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index 7640a815a..ae2e44934 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.TextComponentFactory; +import com.gmail.nossr50.util.skills.RankUtils; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.entity.Player; @@ -40,12 +41,7 @@ public class WoodcuttingCommand extends SkillCommand { // DOUBLE DROPS if (canDoubleDrop) { - if(AdvancedConfig.getInstance().isSubSkillClassic(SubSkillType.WOODCUTTING_HARVEST_LUMBER)) - setDoubleDropClassicChanceStrings(skillValue, isLucky); - else - { - //TODO: Set up datastrings for new harvest - } + setDoubleDropClassicChanceStrings(skillValue, isLucky); } } @@ -58,7 +54,7 @@ public class WoodcuttingCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { canTreeFell = Permissions.treeFeller(player); - canDoubleDrop = Permissions.isSubSkillEnabled(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled(); + canDoubleDrop = Permissions.isSubSkillEnabled(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; canLeafBlow = Permissions.isSubSkillEnabled(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); canSplinter = Permissions.isSubSkillEnabled(player, SubSkillType.WOODCUTTING_SPLINTER); canBarkSurgeon = Permissions.isSubSkillEnabled(player, SubSkillType.WOODCUTTING_BARK_SURGEON); diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 442d18064..344a8d5d7 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -37,11 +37,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { // Validate all the settings! List reason = new ArrayList(); - /* - * In the future this method will check keys for all skills, but for now it only checks overhauled skills - */ - checkKeys(reason); - /* GENERAL */ if (getAbilityLengthRetro() < 1) { reason.add("Skills.General.Ability.Length.RetroMode.IncreaseLevel should be at least 1!"); @@ -814,51 +809,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { return config.getBoolean(keyLocation); }*/ - - /** - * Gets the level required to unlock a subskill at a given rank - * @param subSkillType The subskill - * @param rank The rank of the skill - * @return The level required to use this rank of the subskill - * @deprecated Right now mcMMO is an overhaul process, this will only work for skills I have overhauled. I will be removing the deprecated tag when that is true. - */ - @Deprecated - public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank) - { - /* - * This is a bit messy but - * - * Some skills have per-rank settings as child nodes for Rank_x nodes - * If they do, we have to grab the child node named LevelReq from Rank_x for that skill - * - * Other skills which do not have complex per-rank settings will instead find their Level Requirement returned at Rank_x - */ - if(config.get(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+rank+".LevelReq") != null) - return config.getInt(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+rank+".LevelReq"); - else - return config.getInt(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+rank); - } - - @Deprecated /* NEW VERSION */ - public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) - { - /* - * This is a bit messy but - * - * Some skills have per-rank settings as child nodes for Rank_x nodes - * If they do, we have to grab the child node named LevelReq from Rank_x for that skill - * - * Other skills which do not have complex per-rank settings will instead find their Level Requirement returned at Rank_x - */ - - String key = "Skills."+abstractSubSkill.getPrimaryKeyName()+"."+abstractSubSkill.getConfigKeyName(); - - if(config.get(key + ".Rank_Levels.Rank_"+rank+".LevelReq") != null) - return config.getInt(key + ".Rank_Levels.Rank_"+rank+".LevelReq"); - else - return config.getInt(key + ".Rank_Levels.Rank_"+rank); - } - /** * Some SubSkills have the ability to retain classic functionality * @param subSkillType SubSkillType with classic functionality @@ -1034,39 +984,4 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { public String getPlayerUnleashMessage() { return config.getString("Kraken.Unleashed_Message.Player", ""); } public String getPlayerDefeatMessage() { return config.getString("Kraken.Defeated_Message.Killed", ""); } public String getPlayerEscapeMessage() { return config.getString("Kraken.Defeated_Message.Escape", ""); } - - /** - * Checks for valid keys in the advanced.yml file for subskill ranks - */ - private void checkKeys(List reasons) - { - //For now we will only check ranks of stuff I've overhauled - for(SubSkillType subSkillType : SubSkillType.values()) - { - if(subSkillType.getParentSkill() == PrimarySkillType.WOODCUTTING) - { - //Keeping track of the rank requirements and making sure there are no logical errors - int curRank = 0; - int prevRank = 0; - - for(int x = 0; x < subSkillType.getNumRanks(); x++) - { - if(curRank > 0) - prevRank = curRank; - - curRank = getSubSkillUnlockLevel(subSkillType, x); - - //Do we really care if its below 0? Probably not - if(curRank < 0) - reasons.add(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+curRank+".LevelReq should be above or equal to 0!"); - - if(prevRank > curRank) - { - //We're going to allow this but we're going to warn them - plugin.getLogger().info("You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); - } - } - } - } - } } diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 5dbcd539e..f534f8d36 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -557,9 +557,10 @@ public class Config extends AutoUpdateConfigLoader { return (cap <= 0) ? Integer.MAX_VALUE : cap; } - public int getSkillAbilityGate(PrimarySkillType skill) { + + /*public int isSuperAbilityUnlocked(PrimarySkillType skill) { return config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Ability_Activation_Level_Gate"); - } + }*/ public boolean getTruncateSkills() { return config.getBoolean("General.TruncateSkills", false); } diff --git a/src/main/java/com/gmail/nossr50/config/RankConfig.java b/src/main/java/com/gmail/nossr50/config/RankConfig.java index b9de07c3d..f5a1a7e71 100644 --- a/src/main/java/com/gmail/nossr50/config/RankConfig.java +++ b/src/main/java/com/gmail/nossr50/config/RankConfig.java @@ -1,5 +1,11 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; + +import java.util.ArrayList; +import java.util.List; + public class RankConfig extends AutoUpdateConfigLoader { private static RankConfig instance; @@ -22,4 +28,93 @@ public class RankConfig extends AutoUpdateConfigLoader { return instance; } + + @Override + protected boolean validateKeys() { + List reason = new ArrayList(); + + /* + * In the future this method will check keys for all skills, but for now it only checks overhauled skills + */ + checkKeys(reason); + + return noErrorsInConfig(reason); + } + + /** + * Returns the unlock level for a subskill depending on the gamemode + * @param subSkillType target subskill + * @param rank the rank we are checking + * @return the level requirement for a subskill at this particular rank + */ + public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank) + { + String key = subSkillType.getRankConfigAddress(); + + return findRankByRootAddress(rank, key); + } + + /** + * Returns the unlock level for a subskill depending on the gamemode + * @param abstractSubSkill target subskill + * @param rank the rank we are checking + * @return the level requirement for a subskill at this particular rank + */ + public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) + { + String key = abstractSubSkill.getPrimaryKeyName()+"."+abstractSubSkill.getConfigKeyName(); + + return findRankByRootAddress(rank, key); + } + + /** + * Returns the unlock level for a subskill depending on the gamemode + * @param key root address of the subskill in the rankskills.yml file + * @param rank the rank we are checking + * @return the level requirement for a subskill at this particular rank + */ + private int findRankByRootAddress(int rank, String key) { + String scalingKey = Config.getInstance().getIsRetroMode() ? ".RetroMode." : ".Standard."; + + String targetRank = "Rank_" + rank; + + key += scalingKey; + key += targetRank; + + return config.getInt(key); + } + + /** + * Checks for valid keys for subskill ranks + */ + private void checkKeys(List reasons) + { + //For now we will only check ranks of stuff I've overhauled + for(SubSkillType subSkillType : SubSkillType.values()) + { + //Keeping track of the rank requirements and making sure there are no logical errors + int curRank = 0; + int prevRank = 0; + + for(int x = 0; x < subSkillType.getNumRanks(); x++) + { + if(curRank > 0) + prevRank = curRank; + + curRank = getSubSkillUnlockLevel(subSkillType, x); + + //Do we really care if its below 0? Probably not + if(curRank < 0) + { + reasons.add(subSkillType.getAdvConfigAddress() + ".Rank_Levels.Rank_"+curRank+".LevelReq should be above or equal to 0!"); + } + + if(prevRank > curRank) + { + //We're going to allow this but we're going to warn them + plugin.getLogger().info("You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); + } + } + } + } } 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 f59312d2e..19c990c8e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -44,6 +44,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.gmail.nossr50.util.skills.PerksUtils; +import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -739,19 +740,16 @@ public class McMMOPlayer { return; } - /* - * Check if the player has passed the gate requirement - */ - if(Config.getInstance().getAbilitiesGateEnabled()) - { - if(getSkillLevel(skill) < skill.getSkillAbilityGate()) - { - int diff = skill.getSkillAbilityGate() - getSkillLevel(skill); - //Inform the player they are not yet skilled enough - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getName()); - return; - } + //TODO: This is hacky and temporary solution until skills are move to the new system + //Potential problems with this include skills with two super abilities (ie mining) + if(!skill.isSuperAbilityUnlocked(getPlayer())) + { + int diff = RankUtils.getSuperAbilityUnlockRequirement(skill.getAbility()) - getSkillLevel(skill); + + //Inform the player they are not yet skilled enough + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getName()); + return; } int timeRemaining = calculateTimeRemaining(ability); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index c2dd9fa21..0b91b7d90 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -23,6 +23,7 @@ import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.StringUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; +import com.gmail.nossr50.util.skills.RankUtils; import com.google.common.collect.ImmutableList; import org.bukkit.Color; import org.bukkit.entity.Entity; @@ -40,7 +41,7 @@ public enum PrimarySkillType { AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE, ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_TREASURE_HUNTER)), FISHING(FishingManager.class, Color.NAVY, ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), - HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, ImmutableList.of(SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), + HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), REPAIR(RepairManager.class, Color.SILVER, ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), SALVAGE(SalvageManager.class, Color.ORANGE, ImmutableList.of(SubSkillType.SALVAGE_UNDERSTANDING_THE_ART, SubSkillType.SALVAGE_ADVANCED_SALVAGE, SubSkillType.SALVAGE_ARCANE_SALVAGE)), @@ -124,7 +125,7 @@ public enum PrimarySkillType { return Config.getInstance().getLevelCap(this); } - public int getSkillAbilityGate() { return Config.getInstance().getSkillAbilityGate(this); } + public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getAbility().getSubSkillTypeDefinition()) >= 1; } public boolean getPVPEnabled() { return Config.getInstance().getPVPEnabled(this); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 64c546945..e07b7a4fa 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -11,20 +11,20 @@ public enum SubSkillType { ACROBATICS_ROLL, /* ALCHEMY */ - ALCHEMY_CATALYSIS, + ALCHEMY_CATALYSIS(1), ALCHEMY_CONCOCTIONS(8), /* ARCHERY */ - ARCHERY_DAZE(), + ARCHERY_DAZE, ARCHERY_ARROW_RETRIEVAL, ARCHERY_SKILL_SHOT(20), /* Axes */ - AXES_ARMOR_IMPACT, + AXES_ARMOR_IMPACT(20), AXES_AXE_MASTERY(4), AXES_CRITICAL_STRIKES, AXES_GREATER_IMPACT, - AXES_SKULL_SPLITTER(0), + AXES_SKULL_SPLITTER(1), /* Excavation */ EXCAVATION_TREASURE_HUNTER, @@ -44,11 +44,12 @@ public enum SubSkillType { HERBALISM_DOUBLE_DROPS, HERBALISM_HYLIAN_LUCK, HERBALISM_SHROOM_THUMB, + HERBALISM_GREEN_TERRA, /* Mining */ MINING_DOUBLE_DROPS, - MINING_SUPER_BREAKER(0), - MINING_BLAST_MINING, + MINING_SUPER_BREAKER(1), + MINING_BLAST_MINING(8), MINING_BIGGER_BOMBS, MINING_DEMOLITIONS_EXPERTISE, @@ -60,29 +61,29 @@ public enum SubSkillType { /* Salvage */ SALVAGE_ADVANCED_SALVAGE, SALVAGE_ARCANE_SALVAGE, - SALVAGE_UNDERSTANDING_THE_ART, + SALVAGE_UNDERSTANDING_THE_ART(8), /* Smelting */ SMELTING_FLUX_MINING, SMELTING_FUEL_EFFICIENCY, SMELTING_SECOND_SMELT, - SMELTING_UNDERSTANDING_THE_ART, + SMELTING_UNDERSTANDING_THE_ART(8), /* Swords */ SWORDS_BLEED, SWORDS_COUNTER_ATTACK, - SWORDS_SERRATED_STRIKES, + SWORDS_SERRATED_STRIKES(1), /* Taming */ TAMING_BEAST_LORE, TAMING_CALL_OF_THE_WILD, - TAMING_ENVIRONMENTALLY_AWARE, - TAMING_FAST_FOOD_SERVICE, + TAMING_ENVIRONMENTALLY_AWARE(1), + TAMING_FAST_FOOD_SERVICE(1), TAMING_GORE, - TAMING_HOLY_HOUND, - TAMING_SHARPENED_CLAWS, - TAMING_SHOCK_PROOF, - TAMING_THICK_FUR, + TAMING_HOLY_HOUND(1), + TAMING_SHARPENED_CLAWS(1), + TAMING_SHOCK_PROOF(1), + TAMING_THICK_FUR(1), TAMING_PUMMEL, /* Unarmed */ @@ -91,7 +92,7 @@ public enum SubSkillType { UNARMED_DISARM, UNARMED_IRON_ARM_STYLE, UNARMED_IRON_GRIP, - UNARMED_BERSERK(0), + UNARMED_BERSERK(1), /* Woodcutting */ WOODCUTTING_TREE_FELLER(5), @@ -99,7 +100,7 @@ public enum SubSkillType { WOODCUTTING_BARK_SURGEON(3), WOODCUTTING_NATURES_BOUNTY(3), WOODCUTTING_SPLINTER(3), - WOODCUTTING_HARVEST_LUMBER(3); + WOODCUTTING_HARVEST_LUMBER(1); private final int numRanks; //TODO: SuperAbilityType should also contain flags for active by default? Not sure if it should work that way. @@ -131,13 +132,21 @@ public enum SubSkillType { public PrimarySkillType getParentSkill() { return PrimarySkillType.bySecondaryAbility(this); } /** - * Returns the permission root address for the advanced.yml for this subskill - * @return permission root address in advanced.yml for this subskill + * Returns the root address for this skill in the advanced.yml file + * @return the root address for this skill in advanced.yml */ public String getAdvConfigAddress() { return "Skills." + StringUtils.getCapitalized(getParentSkill().toString()) + "." + getConfigName(toString()); } + /** + * Returns the root address for this skill in the rankskills.yml file + * @return the root address for this skill in rankskills.yml + */ + public String getRankConfigAddress() { + return StringUtils.getCapitalized(getParentSkill().toString()) + "." + getConfigName(toString()); + } + /** * Get the string representation of the permission node for this subskill * @return the permission node for this subskill diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 431d4c522..a7e10d79d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -1,9 +1,15 @@ package com.gmail.nossr50.datatypes.skills; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.subskills.interfaces.SubSkill; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.StringUtils; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.RankUtils; +import com.google.common.collect.ImmutableList; +import jdk.nashorn.internal.ir.annotations.Immutable; import org.bukkit.Material; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; @@ -69,11 +75,27 @@ public enum SuperAbilityType { null), ; + /* + * Defining their associated SubSkillType definitions + * This is a bit of a band-aid fix until the new skill system is in place + */ + static { + BERSERK.subSkillTypeDefinition = SubSkillType.UNARMED_BERSERK; + SUPER_BREAKER.subSkillTypeDefinition = SubSkillType.MINING_SUPER_BREAKER; + GIGA_DRILL_BREAKER.subSkillTypeDefinition = SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER; + GREEN_TERRA.subSkillTypeDefinition = SubSkillType.HERBALISM_GREEN_TERRA; + SKULL_SPLITTER.subSkillTypeDefinition = SubSkillType.AXES_SKULL_SPLITTER; + TREE_FELLER.subSkillTypeDefinition = SubSkillType.WOODCUTTING_TREE_FELLER; + SERRATED_STRIKES.subSkillTypeDefinition = SubSkillType.SWORDS_SERRATED_STRIKES; + BLAST_MINING.subSkillTypeDefinition = SubSkillType.MINING_BLAST_MINING; + } + private String abilityOn; private String abilityOff; private String abilityPlayer; private String abilityRefresh; private String abilityPlayerOff; + private SubSkillType subSkillTypeDefinition; private SuperAbilityType(String abilityOn, String abilityOff, String abilityPlayer, String abilityRefresh, String abilityPlayerOff) { this.abilityOn = abilityOn; @@ -200,4 +222,12 @@ public enum SuperAbilityType { return false; } } + + /** + * Grabs the associated SubSkillType definition for this SuperAbilityType + * @return the matching SubSkillType definition for this SuperAbilityType + */ + public SubSkillType getSubSkillTypeDefinition() { + return subSkillTypeDefinition; + } } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index c7969f296..87add7c43 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -210,7 +210,7 @@ public class mcMMO extends JavaPlugin { placeStore.saveAll(); // Save our metadata placeStore.cleanUp(); // Cleanup empty metadata stores } - catch (NullPointerException e) {} + catch (NullPointerException e) { e.printStackTrace(); } debug("Canceling all tasks..."); getServer().getScheduler().cancelTasks(this); // This removes our tasks diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index 617310d8e..34f464e14 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -64,9 +64,7 @@ public final class Alchemy { List toFinish = new ArrayList(); - for (AlchemyBrewTask alchemyBrewTask : brewingStandMap.values()) { - toFinish.add(alchemyBrewTask); - } + toFinish.addAll(brewingStandMap.values()); for (AlchemyBrewTask alchemyBrewTask : toFinish) { alchemyBrewTask.finishImmediately(); 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 5a57ee764..4ee136270 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.Set; public final class Woodcutting { - public static int leafBlowerUnlockLevel = AdvancedConfig.getInstance().getLeafBlowUnlockLevel(); public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); 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 5680d7be7..0de4e9297 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -13,6 +13,7 @@ import com.gmail.nossr50.skills.woodcutting.Woodcutting.ExperienceGainMethod; import com.gmail.nossr50.util.*; import com.gmail.nossr50.util.player.NotificationManager; 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; @@ -31,7 +32,9 @@ public class WoodcuttingManager extends SkillManager { } public boolean canUseLeafBlower(ItemStack heldItem) { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) && getSkillLevel() >= Woodcutting.leafBlowerUnlockLevel && ItemUtils.isAxe(heldItem); + return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) + && RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.WOODCUTTING_LEAF_BLOWER) + && ItemUtils.isAxe(heldItem); } public boolean canUseTreeFeller(ItemStack heldItem) { @@ -39,7 +42,9 @@ public class WoodcuttingManager extends SkillManager { } protected boolean canGetDoubleDrops() { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && SkillUtils.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer(), this.skill, getSkillLevel(), activationChance); + return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) + && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) + && SkillUtils.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer(), this.skill, getSkillLevel(), activationChance); } /** diff --git a/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java b/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java index 72cec7d4a..74a8a31be 100644 --- a/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/TextComponentFactory.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.commands.skills.McMMOWebLinks; import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.config.RankConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.json.McMMOUrl; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -23,12 +24,6 @@ import java.util.List; * This class handles many of the JSON components that mcMMO makes and uses */ public class TextComponentFactory { - //public static HashMap subSkillTextComponents; - - //Yeah there's probably a better way to do this - //public static HashMap lockedComponentMap; - - //public static BaseComponent[] webComponents; /** * Makes a text component using strings from a locale and supports passing an undefined number of variables to the LocaleLoader @@ -39,20 +34,13 @@ public class TextComponentFactory { */ public static TextComponent getNotificationMultipleValues(String localeKey, NotificationType notificationType, String... values) { - //TODO: Make this colored - String preColoredString = LocaleLoader.getString(localeKey, values); - - /*for(int x = 0; x < values.length; x++) - { - - }*/ - + String preColoredString = LocaleLoader.getString(localeKey, (Object[]) values); return new TextComponent(preColoredString); } public static TextComponent getNotificationTextComponentFromLocale(String localeKey, NotificationType notificationType) { - return getNotificationTextComponent(LocaleLoader.getString(localeKey), notificationType); + return getNotificationTextComponent(LocaleLoader.getString(localeKey)); } public static TextComponent getNotificationLevelUpTextComponent(McMMOPlayer player, PrimarySkillType skill, int currentLevel) @@ -69,47 +57,18 @@ public class TextComponentFactory { return textComponent; } - public static TextComponent getNotificationTextComponent(String text, NotificationType notificationType) + private static TextComponent getNotificationTextComponent(String text) { - TextComponent textComponent = new TextComponent(text); //textComponent.setColor(getNotificationColor(notificationType)); - return textComponent; + return new TextComponent(text); } - /*public static ChatColor getNotificationColor(NotificationType notificationType) - { - ChatColor color = ChatColor.WHITE; - switch(notificationType) - { - case SUPER_ABILITY: - break; - case TOOL: - break; - case SUBSKILL_UNLOCKED: - break; - case SUBSKILL_MESSAGE: - break; - case LEVEL_UP_MESSAGE: - break; - case XP_GAIN: - break; - } - - return color; - }*/ - public static void sendPlayerUrlHeader(Player player) { if(!Config.getInstance().getUrlLinksEnabled()) return; Player.Spigot spigotPlayer = player.spigot(); - /*if(webComponents != null) - { - player.spigot().sendMessage(webComponents); - return; - }*/ - TextComponent prefix = new TextComponent("[| "); prefix.setColor(ChatColor.DARK_AQUA); TextComponent suffix = new TextComponent(" |]"); @@ -137,7 +96,6 @@ public class TextComponentFactory { public static void sendPlayerSubSkillList(Player player, List textComponents) { TextComponent emptySpace = new TextComponent(" "); - //TextComponent atSymbolText = new TextComponent(atSymbol); ArrayList bulkMessage = new ArrayList<>(); int newLineCount = 0; //Hacky solution to wordwrap problems @@ -181,7 +139,7 @@ public class TextComponentFactory { player.spigot().sendMessage(bulkArray); } - public static TextComponent getWebLinkTextComponent(McMMOWebLinks webLinks) + private static TextComponent getWebLinkTextComponent(McMMOWebLinks webLinks) { TextComponent webTextComponent; @@ -227,7 +185,7 @@ public class TextComponentFactory { webTextComponent = new TextComponent("NOT DEFINED"); } - webTextComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, getUrlHoverEvent(webLinks))); + addNewHoverComponentToTextComponent(webTextComponent, getUrlHoverEvent(webLinks)); webTextComponent.setInsertion(webLinks.getUrl()); return webTextComponent; @@ -248,35 +206,38 @@ public class TextComponentFactory { case WEBSITE: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("The official mcMMO Website!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); + componentBuilder.append("\nDev Blogs, and information related to mcMMO can be found here").color(ChatColor.GRAY); break; case SPIGOT: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("The official mcMMO Spigot Resource Page!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); componentBuilder.append("\nI post regularly in the discussion thread here!").color(ChatColor.GRAY); break; case PATREON: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("Support nossr50 and development of mcMMO on Patreon!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); + componentBuilder.append("\n"); + componentBuilder.append("Show support by buying me a coffee :)").italic(false).color(ChatColor.GRAY); break; case WIKI: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("The official mcMMO wiki!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); componentBuilder.append("\n"); componentBuilder.append("I'm looking for more wiki staff, contact me on our discord!").italic(false).color(ChatColor.DARK_GRAY); break; case DISCORD: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("The official mcMMO Discord server!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); break; case HELP_TRANSLATE: addUrlHeaderHover(webLinks, componentBuilder); componentBuilder.append("\n\n").italic(false); - componentBuilder.append("mcMMO's translation service!").color(ChatColor.GREEN); + componentBuilder.append(webLinks.getLocaleDescription()).color(ChatColor.GREEN); componentBuilder.append("\n"); componentBuilder.append("You can use this website to help translate mcMMO into your language!" + "\nIf you want to know more contact me in discord.").italic(false).color(ChatColor.DARK_GRAY); @@ -295,84 +256,85 @@ public class TextComponentFactory { return new ClickEvent(ClickEvent.Action.OPEN_URL, url); } - public static TextComponent getSubSkillTextComponent(Player player, SubSkillType subSkillType) + private static TextComponent getSubSkillTextComponent(Player player, SubSkillType subSkillType) { - - //Get skill name & description from our locale file - //String key = subSkillType.toString(); + //Get skill name String skillName = subSkillType.getLocaleName(); + TextComponent textComponent; //Setup Text Component - TextComponent textComponent = new TextComponent(skillName); - //textComponent.setColor(ChatColor.DARK_AQUA); + if(RankUtils.hasUnlockedSubskill(player, subSkillType)) + { + textComponent = new TextComponent(skillName); + textComponent.setColor(ChatColor.DARK_AQUA); + textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo "+subSkillType.getNiceNameNoSpaces(subSkillType))); + } + else { + textComponent = new TextComponent("???"); + textComponent.setColor(ChatColor.DARK_GRAY); + textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo ???")); + } //Hover Event - textComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, getBaseComponent(player, subSkillType))); + addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, subSkillType)); //Insertion textComponent.setInsertion(skillName); - textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo "+subSkillType.getNiceNameNoSpaces(subSkillType))); return textComponent; } - public static TextComponent getSubSkillTextComponent(Player player, AbstractSubSkill abstractSubSkill) + private static void addNewHoverComponentToTextComponent(TextComponent textComponent, BaseComponent[] baseComponent) { + textComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponent)); + } + + private static TextComponent getSubSkillTextComponent(Player player, AbstractSubSkill abstractSubSkill) { //String key = abstractSubSkill.getConfigKeyName(); String skillName = abstractSubSkill.getNiceName(); //Setup Text Component - TextComponent textComponent = new TextComponent(skillName); - textComponent.setColor(ChatColor.DARK_AQUA); + TextComponent textComponent; + + //Setup Text Component + if(RankUtils.hasUnlockedSubskill(player, abstractSubSkill)) + { + textComponent = new TextComponent(skillName); + textComponent.setColor(ChatColor.DARK_AQUA); + textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo "+abstractSubSkill.getConfigKeyName())); + } + else { + textComponent = new TextComponent("???"); + textComponent.setColor(ChatColor.DARK_GRAY); + textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo ???")); + } //Hover Event - textComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, getBaseComponent(player, abstractSubSkill))); + addNewHoverComponentToTextComponent(textComponent, getSubSkillHoverComponent(player, abstractSubSkill)); //Insertion textComponent.setInsertion(skillName); - textComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/mmoinfo "+abstractSubSkill.getConfigKeyName())); return textComponent; } - private static BaseComponent[] getBaseComponent(Player player, AbstractSubSkill abstractSubSkill) + private static BaseComponent[] getSubSkillHoverComponent(Player player, AbstractSubSkill abstractSubSkill) { - int curRank = RankUtils.getRank(player, abstractSubSkill); - String key = abstractSubSkill.getConfigKeyName(); - - //If the player hasn't unlocked this skill yet we use a different JSON template - if(abstractSubSkill.getNumRanks() > 0 && curRank == 0) - { - BaseComponent[] newComponents = getSubSkillHoverEventJSON(abstractSubSkill, player, curRank); - return newComponents; - } - - return getSubSkillHoverEventJSON(abstractSubSkill, player, curRank); + return getSubSkillHoverEventJSON(abstractSubSkill, player); } - private static BaseComponent[] getBaseComponent(Player player, SubSkillType subSkillType) + private static BaseComponent[] getSubSkillHoverComponent(Player player, SubSkillType subSkillType) { - int curRank = RankUtils.getRank(player, subSkillType); - String key = subSkillType.toString(); - - //If the player hasn't unlocked this skill yet we use a different JSON template - if(subSkillType.getNumRanks() > 0 && curRank == 0) - { - BaseComponent[] newComponents = getSubSkillHoverEventJSON(subSkillType, player, curRank); - return newComponents; - } - - return getSubSkillHoverEventJSON(subSkillType, player, curRank); + return getSubSkillHoverEventJSON(subSkillType, player); } /** * Used for the skill in the new skill system (Deriving from AbstractSubSkill) * @param abstractSubSkill this subskill - * @param player - * @param curRank - * @return + * @param player the player who owns this subskill + * @return the hover basecomponent object for this subskill */ - private static BaseComponent[] getSubSkillHoverEventJSON(AbstractSubSkill abstractSubSkill, Player player, int curRank) + private static BaseComponent[] getSubSkillHoverEventJSON(AbstractSubSkill abstractSubSkill, Player player) { String skillName = abstractSubSkill.getNiceName(); @@ -390,10 +352,15 @@ public class TextComponentFactory { ChatColor ccLevelRequirement = ChatColor.BLUE; ChatColor ccLevelRequired = ChatColor.RED; - //SubSkillType Name - ComponentBuilder componentBuilder = getNewComponentBuilder(skillName, ccSubSkillHeader); + ComponentBuilder componentBuilder; - if(RankUtils.getRank(player, abstractSubSkill) == 0) + //SubSkillType Name + if(RankUtils.hasUnlockedSubskill(player, abstractSubSkill)) + componentBuilder = getNewComponentBuilder(skillName, ccSubSkillHeader); + else + componentBuilder = getNewComponentBuilder("???", ccSubSkillHeader); + + if(!RankUtils.hasUnlockedSubskill(player, abstractSubSkill)) { //Skill is not unlocked yet addLocked(abstractSubSkill, ccLocked, ccLevelRequirement, ccLevelRequired, componentBuilder); @@ -436,15 +403,26 @@ public class TextComponentFactory { } } + private static void addLocked(SubSkillType subSkillType, ChatColor ccLocked, ChatColor ccLevelRequirement, ChatColor ccLevelRequired, ComponentBuilder componentBuilder) { + addLocked(ccLocked, ccLevelRequirement, componentBuilder); + componentBuilder.append(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1))).color(ccLevelRequired); + //componentBuilder.append("\n"); + } + private static void addLocked(AbstractSubSkill abstractSubSkill, ChatColor ccLocked, ChatColor ccLevelRequirement, ChatColor ccLevelRequired, ComponentBuilder componentBuilder) { + addLocked(ccLocked, ccLevelRequirement, componentBuilder); + componentBuilder.append(String.valueOf(RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1))).color(ccLevelRequired); + //componentBuilder.append("\n"); + } + + private static void addLocked(ChatColor ccLocked, ChatColor ccLevelRequirement, ComponentBuilder componentBuilder) { componentBuilder.append(LocaleLoader.getString("JSON.Locked")).color(ccLocked).bold(true); componentBuilder.append("\n").append("\n").bold(false); - componentBuilder.append(LocaleLoader.getString("JSON.LevelRequirement") +": ").color(ccLevelRequirement); - componentBuilder.append(String.valueOf(AdvancedConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, 1))).color(ccLevelRequired); + componentBuilder.append(LocaleLoader.getString("JSON.LevelRequirement") + ": ").color(ccLevelRequirement); } @Deprecated - private static BaseComponent[] getSubSkillHoverEventJSON(SubSkillType subSkillType, Player player, int curRank) + private static BaseComponent[] getSubSkillHoverEventJSON(SubSkillType subSkillType, Player player) { String skillName = subSkillType.getLocaleName(); @@ -462,17 +440,18 @@ public class TextComponentFactory { ChatColor ccLevelRequirement = ChatColor.BLUE; ChatColor ccLevelRequired = ChatColor.RED; - //SubSkillType Name - ComponentBuilder componentBuilder = getNewComponentBuilder(skillName, ccSubSkillHeader); + ComponentBuilder componentBuilder; - if(RankUtils.getRank(player, subSkillType) == 0) + //SubSkillType Name + if(RankUtils.hasUnlockedSubskill(player, subSkillType)) + componentBuilder = getNewComponentBuilder(skillName, ccSubSkillHeader); + else + componentBuilder = getNewComponentBuilder("???", ccSubSkillHeader); + + if(!RankUtils.hasUnlockedSubskill(player, subSkillType)) { //Skill is not unlocked yet - componentBuilder.append(LocaleLoader.getString("JSON.Locked")).color(ccLocked).bold(true); - componentBuilder.append("\n").append("\n").bold(false); - componentBuilder.append(LocaleLoader.getString("JSON.LevelRequirement") +": ").color(ccLevelRequirement); - componentBuilder.append(String.valueOf(AdvancedConfig.getInstance().getSubSkillUnlockLevel(subSkillType, 1))).color(ccLevelRequired); - + addLocked(subSkillType, ccLocked, ccLevelRequirement, ccLevelRequired, componentBuilder); } else { //addSubSkillTypeToHoverEventJSON(subSkillType, componentBuilder); @@ -484,13 +463,13 @@ public class TextComponentFactory { //Empty line componentBuilder.append("\n").bold(false); } - } - componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader")); - componentBuilder.color(ccDescriptionHeader); - componentBuilder.append("\n"); - componentBuilder.append(subSkillType.getLocaleDescription()); - componentBuilder.color(ccDescription); + componentBuilder.append(LocaleLoader.getString("JSON.DescriptionHeader")); + componentBuilder.color(ccDescriptionHeader); + componentBuilder.append("\n"); + componentBuilder.append(subSkillType.getLocaleDescription()); + componentBuilder.color(ccDescription); + } return componentBuilder.create(); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index b29afbe3c..35784537a 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -1,7 +1,8 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.config.RankConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Player; @@ -38,6 +39,58 @@ public class RankUtils { } } + /** + * Returns whether or not the player has unlocked the first rank in target subskill + * @param player the player + * @param subSkillType the target subskill + * @return true if the player has at least one rank in the skill + */ + public static boolean hasUnlockedSubskill(Player player, SubSkillType subSkillType) + { + int curRank = getRank(player, subSkillType); + + //-1 means the skill has no unlockable levels and is therefor unlocked + return curRank == -1 || curRank >= 1; + } + + /** + * Returns whether or not the player has unlocked the first rank in target subskill + * @param player the player + * @param abstractSubSkill the target subskill + * @return true if the player has at least one rank in the skill + */ + public static boolean hasUnlockedSubskill(Player player, AbstractSubSkill abstractSubSkill) + { + int curRank = getRank(player, abstractSubSkill); + + //-1 means the skill has no unlockable levels and is therefor unlocked + return curRank == -1 || curRank >= 1; + } + + /** + * Returns whether or not the player has reached the specified rank in target subskill + * @param rank the target rank + * @param player the player + * @param subSkillType the target subskill + * @return true if the player is at least that rank in this subskill + */ + public static boolean hasReachedRank(int rank, Player player, SubSkillType subSkillType) + { + return getRank(player, subSkillType) >= rank; + } + + /** + * Returns whether or not the player has reached the specified rank in target subskill + * @param rank the target rank + * @param player the player + * @param abstractSubSkill the target subskill + * @return true if the player is at least that rank in this subskill + */ + public static boolean hasReachedRank(int rank, Player player, AbstractSubSkill abstractSubSkill) + { + return getRank(player, abstractSubSkill) >= rank; + } + /** * Gets the current rank of the subskill for the player * @param player The player in question @@ -162,6 +215,23 @@ public class RankUtils { subSkillRanks.put(s, new HashMap<>()); } +/* public static int getSubSkillUnlockRequirement(SubSkillType subSkillType) + { + String skillName = subSkillType.toString(); + int numRanks = subSkillType.getNumRanks(); + + if(subSkillRanks == null) + subSkillRanks = new HashMap<>(); + + if(numRanks == 0) + return -1; //-1 Means the skill doesn't have ranks + + if(subSkillRanks.get(skillName) == null && numRanks > 0) + addRanks(subSkillType); + + return subSkillRanks.get(subSkillType.toString()).get(1); + }*/ + /** * Gets the unlock level for a specific rank in a subskill * @param subSkillType The target subskill @@ -169,13 +239,18 @@ public class RankUtils { * @return The level at which this rank unlocks */ @Deprecated - private static int getUnlockLevel(SubSkillType subSkillType, int rank) + public static int getUnlockLevel(SubSkillType subSkillType, int rank) { - return AdvancedConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank); + return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank); } - private static int getUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) + public static int getUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) { - return AdvancedConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, rank); + return RankConfig.getInstance().getSubSkillUnlockLevel(abstractSubSkill, rank); + } + + public static int getSuperAbilityUnlockRequirement(SuperAbilityType superAbilityType) + { + return getUnlockLevel(superAbilityType.getSubSkillTypeDefinition(), 1); } } diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index a982701e8..34f302e60 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -122,43 +122,11 @@ Skills: MaxBonusLevel: 100 MinSpeed: 1.0 MaxSpeed: 4.0 - - # Rank_Levels: Alchemy level where rank gets unlocked - Rank_Levels: - Rank_1: 0 - Rank_2: 12 - Rank_3: 25 - Rank_4: 37 - Rank_5: 50 - Rank_6: 62 - Rank_7: 75 - Rank_8: 87 # # Settings for Archery ### Archery: SkillShot: - Rank_Levels: - Rank_1: 5 - Rank_2: 10 - Rank_3: 15 - Rank_4: 20 - Rank_5: 25 - Rank_6: 30 - Rank_7: 35 - Rank_8: 40 - Rank_9: 45 - Rank_10: 50 - Rank_11: 55 - Rank_12: 60 - Rank_13: 65 - Rank_14: 70 - Rank_15: 75 - Rank_16: 80 - Rank_17: 85 - Rank_18: 90 - Rank_19: 95 - Rank_20: 100 # RankDamageMultiplier: The current rank of this subskill is multiplied by this value to determine the bonus damage, rank 20 would result in 200% damage increase with a value of 10.0 for RankDamageMultiplier # RankDamageMultiplier is a percentage RankDamageMultiplier: 10.0 @@ -189,11 +157,6 @@ Skills: # This number is multiplied by the current rank the player has in this subskill to find the amount of additional damage to apply # With the default config value of 1.0, at rank 4 a player will deal 4.0 extra damage with Axes (1.0 * 4) RankDamageMultiplier: 1.0 - Rank_Levels: - Rank_1: 5 - Rank_2: 10 - Rank_3: 15 - Rank_4: 20 CriticalStrikes: # ChanceMax: Maximum chance of causing a critical hit when on or higher # MaxBonusLevel: Level where of causing critical hits is reached @@ -226,16 +189,6 @@ Skills: # Settings for Fishing ### Fishing: - # Rank_Levels: Fishing level where rank gets unlocked - Rank_Levels: - Rank_1: 0 - Rank_2: 12 - Rank_3: 25 - Rank_4: 37 - Rank_5: 50 - Rank_6: 62 - Rank_7: 70 - Rank_8: 87 ShakeChance: Rank_1: 15.0 @@ -277,15 +230,11 @@ Skills: # Settings for Herbalism ### Herbalism: - FarmersDiet: - # This determines when Farmers Diet adds extra hunger recovery to food - RankChange: 20 GreenThumb: # StageChange: Level value when the GreenThumb stage rank goes up # ChanceMax: Maximum chance of GreenThumb when on or higher # MaxBonusLevel: On this level, GreenThumb chance will be - StageChange: 20 ChanceMax: 100.0 MaxBonusLevel: 100 @@ -318,15 +267,6 @@ Skills: # BlastMining_Rank: BlastMining rank unlocks BlastMining: - Rank_Levels: - Rank_1: 12 - Rank_2: 25 - Rank_3: 37 - Rank_4: 50 - Rank_5: 62 - Rank_6: 75 - Rank_7: 87 - Rank_8: 100 # BlastDamageDecrease Ranks: % of damage reduced from TNT explosions BlastDamageDecrease: @@ -400,15 +340,6 @@ Skills: ArcaneForging: May_Lose_Enchants: true - Rank_Levels: - Rank_1: 12 - Rank_2: 25 - Rank_3: 37 - Rank_4: 50 - Rank_5: 62 - Rank_6: 75 - Rank_7: 87 - Rank_8: 100 Keep_Enchants_Chance: Rank_1: 10.0 Rank_2: 20.0 @@ -490,17 +421,6 @@ Skills: UnlockLevel: 25 Chance: 33.0 - # Rank_Levels: Smelting level where rank gets unlocked - Rank_Levels: - Rank_1: 12 - Rank_2: 25 - Rank_3: 37 - Rank_4: 50 - Rank_5: 62 - Rank_6: 75 - Rank_7: 87 - Rank_8: 100 - # VanillaXPMultiplier: Vanilla XP gained from smelting ores is multiplied by these values. VanillaXPMultiplier: Rank_1: 1 @@ -630,14 +550,6 @@ Skills: # Settings for Woodcutting ### Woodcutting: - Splinter: - Rank_Levels: - Rank_1: - LevelReq: 5 - Rank_2: - LevelReq: 30 - Rank_3: - LevelReq: 55 TreeFeller: # If set to true then tree feller will not use the new system and will use its old behaviour Classic: false @@ -645,64 +557,27 @@ Skills: ChargeRate: 600 Rank_Levels: Rank_1: - LevelReq: 10 TreeSizeMax: 100 Charges: 1 Rank_2: - LevelReq: 25 TreeSizeMax: 200 Charges: 1 Rank_3: - LevelReq: 50 TreeSizeMax: 200 Charges: 2 Rank_4: - LevelReq: 75 TreeSizeMax: 200 Charges: 3 Rank_5: - LevelReq: 100 TreeSizeMax: 500 Charges: 3 - BarkSurgeon: - Rank_Levels: - Rank_1: - LevelReq: 70 - Rank_2: - LevelReq: 80 - Rank_3: - LevelReq: 95 - NaturesBounty: - Rank_Levels: - Rank_1: - LevelReq: 40 - Rank_2: - LevelReq: 60 - Rank_3: - LevelReq: 90 # Double Drops HarvestLumber: - Classic: false # ChanceMax & MaxBonusLevel are only used for Classic, I'll make that more clear in the future. # ChanceMax: Maximum chance of receiving double drops (100 = 100%) # MaxBonusLevel: Level when the maximum chance of receiving double drops is reached ChanceMax: 100.0 MaxBonusLevel: 100 - Rank_Levels: - Rank_1: - LevelReq: 20 - Rank_2: - LevelReq: 45 - Rank_3: - LevelReq: 85 - LeafBlower: - Rank_Levels: - Rank_1: - LevelReq: 15 - Rank_2: - LevelReq: 35 - Rank_3: - LevelReq: 65 Style: JSON: Notification: diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3f1fa197d..2a4ebb8e4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -277,8 +277,6 @@ Abilities: Enabled: true Messages: true Activation: - # If set to true, abilities will not be available until they meet specific level requirements to use - Level_Gate_Abilities: true Only_Activate_When_Sneaking: false Cooldowns: Berserk: 240 diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 56f69fba9..151758790 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -40,6 +40,12 @@ JSON.Taming=Taming JSON.Unarmed=Unarmed JSON.Woodcutting=Woodcutting JSON.LevelUp=increased to +JSON.URL.Website=The official mcMMO Website! +JSON.URL.Discord=The official mcMMO Discord server! +JSON.URL.Patreon=Support nossr50 and his work for mcMMO on Patreon! +JSON.URL.Spigot=The official mcMMO Spigot Resource Page! +JSON.URL.Translation=Translate mcMMO into other languages! +JSON.URL.Wiki=The official mcMMO wiki! #This is the message sent to players when an ability is activated JSON.Notification.SuperAbility={0} @@ -634,6 +640,7 @@ Commands.Usage.Skill=skill Commands.Usage.SubSkill=subskill Commands.Usage.XP=xp Commands.Description.mmoinfo=Read details about a skill or mechanic. +Commands.MmoInfo.Mystery=[[GRAY]]You haven't unlocked this skill yet, but when you do you will be able to read details about it here! Commands.MmoInfo.NoMatch=That subskill doesn't exist! Commands.MmoInfo.Header=[[DARK_AQUA]]-=[]=====[][[GOLD]] MMO Info [[DARK_AQUA]][]=====[]=- Commands.MmoInfo.SubSkillHeader=[[GOLD]]Name:[[YELLOW]] {0} diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 558ea9518..a89e839d1 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -3,13 +3,12 @@ # You can however, change when they unlock, if you make all ranks of a skill level 0 for example every player will have the most powerful version of that skill right away. # Retro Mode and Standard have separate config settings to make it easier for server owners to understand the difference between the two # Retro Mode is setup to be an entirely cosmetic change, keeping the old 0-1000 feeling of mcMMO -# Retro Mode has 10x faster leveling and 10x higher skill requirements, if you do the math you can see its the same as Standard other than cosmetics! +# Retro Mode has 10x faster leveling and 10x higher skill requirements, if you do the math you can see its the same as Standrd and only cosmetic! ### Alchemy: - Alchemy: - Catalysis: - Standard: - Rank_1: 10 + Catalysis: + Standard: + Rank_1: 10 RetroMode: Rank_1: 100 Concoctions: @@ -55,7 +54,7 @@ Archery: Rank_19: 95 Rank_20: 100 Retro: - Rank_1: 5 + Rank_1: 50 Rank_2: 100 Rank_3: 150 Rank_4: 200 @@ -76,6 +75,11 @@ Archery: Rank_19: 950 Rank_20: 1000 Axes: + SkullSplitter: + Standard: + Rank_1: 10 + RetroMode: + Rank_1: 100 ArmorImpact: Standard: Rank_1: 5 @@ -99,7 +103,7 @@ Axes: Rank_19: 95 Rank_20: 100 Retro: - Rank_1: 5 + Rank_1: 50 Rank_2: 100 Rank_3: 150 Rank_4: 200 @@ -202,6 +206,11 @@ Salvage: Rank_7: 850 Rank_8: 1000 Mining: + SuperBreaker: + Standard: + Rank_1: 10 + RetroMode: + Rank_1: 100 BlastMining: Standard: Rank_1: 10 @@ -222,6 +231,11 @@ Mining: Rank_7: 850 Rank_8: 1000 Herbalism: + GreenTerra: + Standard: + Rank_1: 10 + RetroMode: + Rank_1: 100 GreenThumb: Standard: Rank_1: 20 @@ -291,3 +305,70 @@ Fishing: Rank_6: 750 Rank_7: 850 Rank_8: 1000 +Swords: + SerratedStrikes: + Standard: + Rank_1: 10 + RetroMode: + Rank_1: 100 +Unarmed: + Berserk: + Standard: + Rank_1: 10 + RetroMode: + Rank_1: 100 +Woodcutting: + Splinter: + Standard: + Rank_1: 5 + Rank_2: 30 + Rank_3: 55 + RetroMode: + Rank_1: 50 + Rank_2: 300 + Rank_3: 550 + TreeFeller: + Standard: + Rank_1: 10 + Rank_2: 25 + Rank_3: 50 + Rank_4: 75 + Rank_5: 100 + RetroMode: + Rank_1: 100 + Rank_2: 250 + Rank_3: 500 + Rank_4: 750 + Rank_5: 1000 + BarkSurgeon: + Standard: + Rank_1: 70 + Rank_2: 80 + Rank_3: 95 + RetroMode: + Rank_1: 700 + Rank_2: 800 + Rank_3: 950 + NaturesBounty: + Standard: + Rank_1: 40 + Rank_2: 60 + Rank_3: 90 + RetroMode: + Rank_1: 400 + Rank_2: 600 + Rank_3: 900 + HarvestLumber: + Standard: + Rank_1: 1 + RetroMode: + Rank_1: 10 + LeafBlower: + Standard: + Rank_1: 15 + Rank_2: 35 + Rank_3: 65 + RetroMode: + Rank_1: 150 + Rank_2: 350 + Rank_3: 650 \ No newline at end of file