diff --git a/Changelog.txt b/Changelog.txt index 4982ce7ac..513e050ee 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -9,6 +9,12 @@ Key: Version 2.1.0 + Added config setting to enable or disable classic mcMMO mode + + (Config) Added rank settings for the new Woodcutting skill + + (Config) Added configurable parameters for the new Tree Feller + + (Config) Added classic toggle for Tree Feller + + (Permissions) Added permission nodes for Harvest Lumber, Splinter, Nature's Bounty, and Bark Surgeon + ! Woodcutting's Double Drop subskill is now named Harvest Lumber + ! Replaced the old Double Drop permission node for woodcutting with a new Harvest Lumber permission node ! (API) SkillType is now PrimarySkill ! (API) SecondarySkill is now SubSkill ! (API) AbilityType is now SuperAbility 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 286bb92a6..19da72db2 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -4,7 +4,10 @@ import java.util.ArrayList; import java.util.List; import com.gmail.nossr50.datatypes.skills.PrimarySkill; +import com.gmail.nossr50.datatypes.skills.SkillMilestone; import com.gmail.nossr50.datatypes.skills.SubSkill; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillMilestoneFactory; import org.bukkit.entity.Player; import com.gmail.nossr50.config.AdvancedConfig; @@ -20,6 +23,9 @@ public class WoodcuttingCommand extends SkillCommand { private boolean canTreeFell; private boolean canLeafBlow; private boolean canDoubleDrop; + private boolean canSplinter; + private boolean canBarkSurgeon; + private boolean canNaturesBounty; public WoodcuttingCommand() { super(PrimarySkill.WOODCUTTING); @@ -36,17 +42,29 @@ public class WoodcuttingCommand extends SkillCommand { // DOUBLE DROPS if (canDoubleDrop) { - String[] doubleDropStrings = calculateAbilityDisplayValues(skillValue, SubSkill.WOODCUTTING_DOUBLE_DROPS, isLucky); - doubleDropChance = doubleDropStrings[0]; - doubleDropChanceLucky = doubleDropStrings[1]; + if(AdvancedConfig.getInstance().isSubSkillClassic(SubSkill.WOODCUTTING_HARVEST_LUMBER)) + setDoubleDropClassicChanceStrings(skillValue, isLucky); + else + { + //TODO: Set up datastrings for new harvest + } } } + private void setDoubleDropClassicChanceStrings(float skillValue, boolean isLucky) { + String[] doubleDropStrings = calculateAbilityDisplayValues(skillValue, SubSkill.WOODCUTTING_HARVEST_LUMBER, isLucky); + doubleDropChance = doubleDropStrings[0]; + doubleDropChanceLucky = doubleDropStrings[1]; + } + @Override protected void permissionsCheck(Player player) { canTreeFell = Permissions.treeFeller(player); - canDoubleDrop = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled(); + canDoubleDrop = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled(); canLeafBlow = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_LEAF_BLOWER); + canSplinter = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_SPLINTER); + canBarkSurgeon = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_BARK_SURGEON); + canNaturesBounty = Permissions.isSubSkillEnabled(player, SubSkill.WOODCUTTING_NATURES_BOUNTY); } @Override @@ -65,6 +83,20 @@ public class WoodcuttingCommand extends SkillCommand { messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.4"), LocaleLoader.getString("Woodcutting.Effect.5"))); } + if (canSplinter) { + messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.6"), LocaleLoader.getString("Woodcutting.Effect.7"))); + } + + if(canBarkSurgeon) { + messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.8"), LocaleLoader.getString("Woodcutting.Effect.9"))); + } + + if(canNaturesBounty) { + messages.add(LocaleLoader.getString("Effects.Template", LocaleLoader.getString("Woodcutting.Effect.10"), LocaleLoader.getString("Woodcutting.Effect.11"))); + } + + + return messages; } diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 4da7f5845..efdf198c2 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import com.gmail.nossr50.datatypes.skills.PrimarySkill; import com.gmail.nossr50.datatypes.skills.SubSkill; import com.gmail.nossr50.skills.alchemy.Alchemy; import com.gmail.nossr50.skills.fishing.Fishing; @@ -33,6 +34,11 @@ 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 (getAbilityLength() < 1) { reason.add("Skills.General.Ability.IncreaseLevel should be at least 1!"); @@ -648,16 +654,17 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { } /* WOODCUTTING */ + if (getLeafBlowUnlockLevel() < 0) { reason.add("Skills.Woodcutting.LeafBlower.UnlockLevel should be at least 0!"); } - if (getMaxChance(SubSkill.WOODCUTTING_DOUBLE_DROPS) < 1) { - reason.add("Skills.Woodcutting.DoubleDrops.ChanceMax should be at least 1!"); + if (getMaxChance(SubSkill.WOODCUTTING_HARVEST_LUMBER) < 1) { + reason.add("Skills.Woodcutting.HarvestLumber.ChanceMax should be at least 1!"); } - if (getMaxBonusLevel(SubSkill.WOODCUTTING_DOUBLE_DROPS) < 1) { - reason.add("Skills.Woodcutting.DoubleDrops.MaxBonusLevel should be at least 1!"); + if (getMaxBonusLevel(SubSkill.WOODCUTTING_HARVEST_LUMBER) < 1) { + reason.add("Skills.Woodcutting.HarvestLumber.MaxBonusLevel should be at least 1!"); } /* KRAKEN */ @@ -690,6 +697,30 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { public int getMaxBonusLevel(SubSkill subSkill) { return config.getInt(subSkill.getAdvConfigAddress() + ".MaxBonusLevel"); } public double getMaxChance(SubSkill subSkill) { return config.getDouble(subSkill.getAdvConfigAddress() + ".ChanceMax", 100.0D);} + + /** + * Gets the level required to unlock a subskill at a given rank + * @param subSkill 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(SubSkill subSkill, int rank) + { + return config.getInt(subSkill.getAdvConfigAddress() + ".Rank_Levels.Rank_"+rank+".LevelReq"); + } + + /** + * Some SubSkills have the ability to retain classic functionality + * @param subSkill SubSkill with classic functionality + * @return true if the subskill is in classic mode + */ + public boolean isSubSkillClassic(SubSkill subSkill) + { + return config.getBoolean(subSkill.getAdvConfigAddress()+".Classic"); + } + /* ACROBATICS */ public double getDodgeDamageModifier() { return config.getDouble("Skills.Acrobatics.Dodge.DamageModifier", 2.0D); } @@ -857,4 +888,39 @@ 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(SubSkill subSkill : SubSkill.values()) + { + if(subSkill.getParentSkill() == PrimarySkill.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 < subSkill.getNumRanks(); x++) + { + if(curRank > 0) + prevRank = curRank; + + curRank = getSubSkillUnlockLevel(subSkill, x); + + //Do we really care if its below 0? Probably not + if(curRank < 0) + reasons.add(subSkill.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 "+subSkill.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 e6dfbe882..7e4341eed 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -244,8 +244,16 @@ public class Config extends AutoUpdateConfigLoader { */ /* General Settings */ + //Classic mode will default the value to true if the config file doesn't contain the entry (server is from a previous mcMMO install) public boolean getClassicMode() { return config.getBoolean("General.Classic_Mode", true); } + + //XP needed to level is multiplied by this when using classic mode + public int getClassicModeXPFormulaFactor() { return config.getInt("General.Skill_Scaling.Classic_XP_Formula_Factor", 1); } + + //Level requirements for subskills is multiplied by this when using classic mode + public int getClassicModeLevelReqFactor() { return config.getInt("General.Skill_Scaling.Classic_LevelReq_Factor", 10); } + public String getLocale() { return config.getString("General.Locale", "en_us"); } public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); } public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkill.java index 8b3ddff0c..7a70991ba 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkill.java @@ -50,7 +50,7 @@ public enum PrimarySkill { SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbility.SERRATED_STRIKES, ToolType.SWORD, ImmutableList.of(SubSkill.SWORDS_BLEED, SubSkill.SWORDS_COUNTER)), TAMING(TamingManager.class, Color.PURPLE, ImmutableList.of(SubSkill.TAMING_BEAST_LORE, SubSkill.TAMING_CALL_OF_THE_WILD, SubSkill.TAMING_ENVIRONMENTALLY_AWARE, SubSkill.TAMING_FAST_FOOD, SubSkill.TAMING_GORE, SubSkill.TAMING_HOLY_HOUND, SubSkill.TAMING_SHARPENED_CLAWS, SubSkill.TAMING_SHOCK_PROOF, SubSkill.TAMING_THICK_FUR, SubSkill.TAMING_PUMMEL)), UNARMED(UnarmedManager.class, Color.BLACK, SuperAbility.BERSERK, ToolType.FISTS, ImmutableList.of(SubSkill.UNARMED_BLOCK_CRACKER, SubSkill.UNARMED_DEFLECT, SubSkill.UNARMED_DISARM, SubSkill.UNARMED_IRON_ARM, SubSkill.UNARMED_IRON_GRIP)), - WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbility.TREE_FELLER, ToolType.AXE, ImmutableList.of(SubSkill.WOODCUTTING_LEAF_BLOWER, SubSkill.WOODCUTTING_DOUBLE_DROPS)); + WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbility.TREE_FELLER, ToolType.AXE, ImmutableList.of(SubSkill.WOODCUTTING_LEAF_BLOWER, SubSkill.WOODCUTTING_BARK_SURGEON, SubSkill.WOODCUTTING_SPLINTER, SubSkill.WOODCUTTING_NATURES_BOUNTY, SubSkill.WOODCUTTING_TREE_FELLER, SubSkill.WOODCUTTING_HARVEST_LUMBER)); private Class managerClass; private Color runescapeColor; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SkillMilestone.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SkillMilestone.java index 654423b62..9e8492ab3 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SkillMilestone.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SkillMilestone.java @@ -1,39 +1,106 @@ package com.gmail.nossr50.datatypes.skills; +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.datatypes.player.PlayerProfile; + /** * This class represents a gated subskill - * A gated subskill is a subskill that requires a certain level to unlock + * A SkillMilestone is a representation of a specific rank for a subskill + * A SkillMilestone may contain a child, the child represents the next rank of the subskill * This class is mostly to make it easier to grab information about subskills for a player */ public class SkillMilestone { - private int unlockLevel; //Level that grants access to this skill - private SubSkill subskill; //Subskill that this milestone belongs to + private final int unlockLevel; //Level that grants access to this skill + private final SubSkill subskill; //Subskill that this milestone belongs to private SkillMilestone childMilestone; //Next rank in the milestone + private SkillMilestone lastChild; //The final child milestone in this chain + private final int curRank; //The current rank of this SkillMilestone - public SkillMilestone(SubSkill subskill, int unlockLevel, SkillMilestone childMilestone) + public SkillMilestone(SubSkill subskill, int curRank) { this.subskill = subskill; - this.unlockLevel = unlockLevel; - - //Assign a child subskill if it exists - if(childMilestone != null) - this.childMilestone = childMilestone; - } - - public SkillMilestone(SubSkill subskill, int unlockLevel) - { - this(subskill, unlockLevel, null); + this.curRank = curRank; + this.unlockLevel = AdvancedConfig.getInstance().getSubSkillUnlockLevel(subskill, curRank); } + /** + * Gets the level requirement for this subskill's rank + * @return The level required to use this subskill + */ public int getUnlockLevel() { return unlockLevel; } + /** + * Get's the current milestone the player is working towards + * @param playerProfile + * @return + */ + public SkillMilestone getCurrentMilestoneForPlayer(PlayerProfile playerProfile) + { + if(playerProfile.getSkillLevel(subskill.getParentSkill()) >= unlockLevel) + { + if(childMilestone != null) + return childMilestone.getCurrentMilestoneForPlayer(playerProfile); + + return this; + } else { + return this; + } + } + + /** + * Gets the associated SubSkill for this milestone + * @return + */ public SubSkill getSubskill() { return subskill; } + /** + * Gets the child milestone, which is the next rank of this skill + * @return The child milestone of this skill + */ public SkillMilestone getChildMilestone() { return childMilestone; } + + /** + * Adds a child milestone, which represents the next rank of this skill + */ + public void addChildMilestone() + { + childMilestone = new SkillMilestone(this.subskill, curRank+1); + } + + /** + * This grabs the final child in the chain of child milestones, which represents the last rank of this subskill + * @return The final child for this SkillMilestone, which is the final rank for the associated subskill. Null if this Milestone has no children. + */ + public SkillMilestone getFinalChild() + { + //Return lastchild if we already have the ref stored + if(lastChild != null) + return lastChild; + + //If the next child doesn't exist return this + if(childMilestone == null) { + return this; + } + + //If we have children, find their children until the chain stops and store that reference and return it + return lastChild = childMilestone.getFinalChild(); + } + + /** + * Gets the current rank of this SkillMilestone for the associated subskill + * @return The current rank of this subskill + */ + public int getCurRank() { return curRank; } + + /** + * The requirement for the next rank of this subskill + * @return The level requirement for the next rank of this SkillMilestone chain + */ + public int getNextRankReq() { return childMilestone.unlockLevel; } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkill.java index bc6a588f1..0716e8c45 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkill.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.datatypes.skills; import com.gmail.nossr50.util.StringUtils; -import com.gmail.nossr50.datatypes.skills.PrimarySkill.*; public enum SubSkill { /* !! Warning -- Do not let subskills share a name with any existing PrimarySkill as it will clash with the static import !! */ @@ -85,12 +84,38 @@ public enum SubSkill { UNARMED_IRON_GRIP, /* Woodcutting */ - WOODCUTTING_TREE_FELLER, - WOODCUTTING_LEAF_BLOWER, - WOODCUTTING_SURGEON, - WOODCUTTING_NATURES_BOUNTY, - WOODCUTTING_SPLINTER, - WOODCUTTING_DOUBLE_DROPS; + WOODCUTTING_TREE_FELLER(5), + WOODCUTTING_LEAF_BLOWER(3), + WOODCUTTING_BARK_SURGEON(3), + WOODCUTTING_NATURES_BOUNTY(3), + WOODCUTTING_SPLINTER(3), + WOODCUTTING_HARVEST_LUMBER(3); + + private final int numRanks; + + /** + * If our SubSkill has more than 1 rank define it + * @param numRanks The number of ranks our SubSkill has + */ + SubSkill(int numRanks) + { + this.numRanks = numRanks; + } + + /** + * SubSkills will default to having only 1 rank if not defined + */ + SubSkill() + { + this.numRanks = 1; + } + + + + public int getNumRanks() + { + return numRanks; + } /** * !!! This relies on the immutable lists in PrimarySkill being populated !!! @@ -136,7 +161,7 @@ public enum SubSkill { * Find where to begin our substring (after the prefix) */ String endResult = ""; - char[] enumNameCharArray = subSkillName.toString().toCharArray(); + char[] enumNameCharArray = subSkillName.toCharArray(); int subStringIndex = 0; //Find where to start our substring for this constants name @@ -152,12 +177,17 @@ public enum SubSkill { /* * Split the string up so we can capitalize each part */ - String subskillNameWithoutPrefix = subSkillName.toString().substring(subStringIndex); - String splitStrings[] = subskillNameWithoutPrefix.split("_"); - - for(String string : splitStrings) + String subskillNameWithoutPrefix = subSkillName.substring(subStringIndex); + if(subskillNameWithoutPrefix.contains("_")) { - endResult += StringUtils.getCapitalized(string); + String splitStrings[] = subskillNameWithoutPrefix.split("_"); + + for(String string : splitStrings) + { + endResult += StringUtils.getCapitalized(string); + } + } else { + endResult += StringUtils.getCapitalized(subskillNameWithoutPrefix); } return endResult; diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index a6ae67b17..de346bbdc 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -47,7 +47,6 @@ import net.shatteredlands.shatt.backup.ZipLibrary; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; @@ -189,9 +188,6 @@ public class mcMMO extends JavaPlugin { getServer().getPluginManager().disablePlugin(this); } - - //Grab the setting for classic mode - classicModeEnabled = Config.getInstance().getClassicMode(); } /** 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 1ff34a4f7..08cb906f6 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -38,7 +38,7 @@ public class WoodcuttingManager extends SkillManager { } protected boolean canGetDoubleDrops() { - return Permissions.isSubSkillEnabled(getPlayer(), SubSkill.WOODCUTTING_DOUBLE_DROPS) && SkillUtils.isActivationSuccessful(SubSkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkill.WOODCUTTING_DOUBLE_DROPS, getPlayer(), this.skill, getSkillLevel(), activationChance); + return Permissions.isSubSkillEnabled(getPlayer(), SubSkill.WOODCUTTING_HARVEST_LUMBER) && SkillUtils.isActivationSuccessful(SubSkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkill.WOODCUTTING_HARVEST_LUMBER, getPlayer(), this.skill, getSkillLevel(), activationChance); } /** diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index c28e04941..ce33b629b 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -21,7 +21,14 @@ public class FormulaManager { private FormulaType previousFormula; + //Used for XP formula scaling + private boolean classicModeEnabled; + private int classicModeXPFormulaFactor; + public FormulaManager() { + /* Setting for Classic Mode (Scales a lot of stuff up by * 10) */ + classicModeEnabled = Config.getInstance().getClassicMode(); + classicModeXPFormulaFactor = Config.getInstance().getClassicModeXPFormulaFactor(); loadFormula(); } @@ -105,6 +112,9 @@ public class FormulaManager { public int getCachedXpToLevel(int level, FormulaType formulaType) { int experience; + //If we're in classic we use the XP factor from config settings + int skillSystemMultiplier = classicModeEnabled ? classicModeXPFormulaFactor : 10; + if (formulaType == FormulaType.UNKNOWN) { formulaType = FormulaType.LINEAR; } @@ -116,7 +126,7 @@ public class FormulaManager { switch (formulaType) { case LINEAR: if (!experienceNeededLinear.containsKey(level)) { - experience = (int) Math.floor( 10 * (base + level * multiplier)); + experience = (int) Math.floor( skillSystemMultiplier * (base + level * multiplier)); experienceNeededLinear.put(level, experience); } @@ -124,7 +134,7 @@ public class FormulaManager { case EXPONENTIAL: if (!experienceNeededExponential.containsKey(level)) { - experience = (int) Math.floor( 10 * multiplier * Math.pow(level, exponent) + base); + experience = (int) Math.floor( skillSystemMultiplier * (multiplier * Math.pow(level, exponent) + base)); experienceNeededExponential.put(level, experience); } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillMilestoneFactory.java b/src/main/java/com/gmail/nossr50/util/skills/SkillMilestoneFactory.java new file mode 100644 index 000000000..6ba4a3a01 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillMilestoneFactory.java @@ -0,0 +1,55 @@ +package com.gmail.nossr50.util.skills; + +import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.datatypes.skills.SkillMilestone; +import com.gmail.nossr50.datatypes.skills.SubSkill; + +import java.util.HashMap; + +/** + * This Factory class builds SkillMilestone chains as needed + * SkillMilestones are stored in a hash map + */ +public class SkillMilestoneFactory { + + private static HashMap skillMilestoneMap; + + /** + * Gets a the SkillMilestone chain for this subskill + * Builds that chain if it doesn't exist before returning the parent node + * @param subSkill The SubSkill to get the SkillMilestone chain for + * @return The parent node of the SkillMilestone chain for the target subskill + */ + public static SkillMilestone getSkillMilestone(SubSkill subSkill) + { + //Init the map + if(skillMilestoneMap == null) + skillMilestoneMap = new HashMap<>(); + + if(skillMilestoneMap.get(subSkill) == null) + return buildSkillMilestone(subSkill); + else + return skillMilestoneMap.get(subSkill); + } + + /** + * Constructs a SkillMilestone chain for a given subskill + * @param subSkill The subskill to build the SkillMilestone chain for + * @return The base node of the SkillMilestone chain + */ + private static SkillMilestone buildSkillMilestone(SubSkill subSkill) + { + //Init our parent node + SkillMilestone newSkillMilestone = new SkillMilestone(subSkill, AdvancedConfig.getInstance().getSubSkillUnlockLevel(subSkill, 1)); + + //There's probably a better way to do this + for(int x = 0; x < subSkill.getNumRanks()-1; x++) + { + newSkillMilestone.addChildMilestone(); + } + + //DEBUG + System.out.println("Milestone constructed for "+subSkill); + return skillMilestoneMap.put(subSkill, newSkillMilestone); + } +} \ No newline at end of file diff --git a/src/main/resources/advanced.yml b/src/main/resources/advanced.yml index ff9b28525..70b767e7f 100644 --- a/src/main/resources/advanced.yml +++ b/src/main/resources/advanced.yml @@ -564,15 +564,80 @@ Skills: # Settings for Woodcutting ### Woodcutting: - LeafBlower: - # UnlockLevel: At this level, the passive ability LeafBlower unlocks - UnlockLevel: 100 - - DoubleDrops: - # ChanceMax: Maximum chance of receiving double drops + 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 + # This is the time in seconds to build a new charge of Tree Feller + 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 + # # Customize the kraken! ### diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b0e4aa1aa..e35410c06 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,7 +8,14 @@ # Settings for mcMMO in general ### General: - Classic_Mode: false + Skill_Scaling: + # Turning this on will scale mcMMO around 1-1000 with default scaling factor + Classic_Mode: false + Skill_Scaling: + # This is the value that is skill level requirements are multiplied by in Classic Mode (Default is 10) + Classic_LevelReq_Factor: 10 + # This is the value that the xp required to level is multiplied by when in classic mode + Classic_XP_Formula_Factor: 1 Locale: en_US MOTD_Enabled: true # Send a message to the player when his profile was successfully loaded diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index e1cdd3846..ab9c97dea 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -408,8 +408,14 @@ Woodcutting.Effect.0=Tree Feller (ABILITY) Woodcutting.Effect.1=Make trees explode Woodcutting.Effect.2=Leaf Blower Woodcutting.Effect.3=Blow Away Leaves -Woodcutting.Effect.4=Double Drops -Woodcutting.Effect.5=Double the normal loot +Woodcutting.Effect.4=Harvest Lumber +Woodcutting.Effect.5=Skillfully extract more Lumber +Woodcutting.Effect.6=Splinter +Woodcutting.Effect.7=Cut down trees more efficiently. +Woodcutting.Effect.8=Bark Surgeon +Woodcutting.Effect.9=Extract useful materials when stripping trees. +Woodcutting.Effect.10=Nature's Bounty +Woodcutting.Effect.11=Gather experience from nature. Woodcutting.Listener=Woodcutting: Woodcutting.SkillName=WOODCUTTING Woodcutting.Skills.TreeFeller.Off=[[RED]]**Tree Feller has worn off** diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 30d5b08cd..00dfe4441 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -12,7 +12,7 @@ description: > author: nossr50 authors: [GJ, NuclearW, bm01, Glitchfinder, TfT_02, t00thpick1, Riking] -website: https://github.com/mcMMO-Dev/mcMMO +website: https://mcmmo.org main: com.gmail.nossr50.mcMMO softdepend: [CombatTag, HealthBar] load: STARTUP @@ -668,10 +668,19 @@ permissions: mcmmo.ability.woodcutting.all: description: Allows access to all Woodcutting abilities children: - mcmmo.ability.woodcutting.doubledrops: true + mcmmo.ability.woodcutting.harvestlumber: true + mcmmo.ability.woodcutting.splinter: true + mcmmo.ability.woodcutting.barksurgeon: true + mcmmo.ability.woodcutting.naturesbounty: true mcmmo.ability.woodcutting.leafblower: true mcmmo.ability.woodcutting.treefeller: true - mcmmo.ability.woodcutting.doubledrops: + mcmmo.ability.woodcutting.splinter: + description: Allows access to Splinter + mcmmo.ability.woodcutting.barksurgeon: + description: Allows access to Bark Surgeon + mcmmo.ability.woodcutting.naturesbounty: + description: Allows access to Natures Bounty + mcmmo.ability.woodcutting.harvestlumber: description: Allows double drop chance when woodcutting mcmmo.ability.woodcutting.leafblower: description: Allows access to Leaf Blower ability