diff --git a/Changelog.txt b/Changelog.txt
index 188e1f93b..14c4c9b61 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,3 +1,11 @@
+Version 2.1.64
+ (API) method to get XP in FormulaManager has been renamed to getXPtoNextLevel(...), this shouldn't break anything as plugins should be using our Experience API methods instead of this
+ (API) Added method getLevel(Player player, PrimarySkillType primarySkillType) to ExperienceAPI.java
+ Corrected how Standard mode (1-100 scaling) XP to next level was calculated, it is now a true 1:10 ratio with Retro (1-1000) scale, which is how it was intended to be to begin with
+
+ NOTE: The net result of this change is it will take a bit longer to level with Standard, but it should not be a drastic change. You might not even notice it.
+ Standard is meant to take the same amount of time to level from levels 1-100 as it takes Retro to do 1-1000, this change corrects from errors in the code that made Standard actually take less XP than Retro despite intending for it to be a cosmetic difference in progression.
+
Version 2.1.63
Fixed Armor Impact not scaling by skill rank
Significantly Buffed the amount of durability damage incurred by a successful Armor Impact
diff --git a/pom.xml b/pom.xml
index 6670f853a..d7cd7c2de 100755
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.gmail.nossr50.mcMMO
mcMMO
- 2.1.63
+ 2.1.64-SNAPSHOT
mcMMO
https://github.com/mcMMO-Dev/mcMMO
@@ -167,7 +167,7 @@
org.spigotmc
spigot-api
- 1.14.1-R0.1-SNAPSHOT
+ 1.14.2-R0.1-SNAPSHOT
provided
diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
index 93eaef9a3..e018a4cc2 100644
--- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
+++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
@@ -649,11 +649,28 @@ public final class ExperienceAPI {
* @return the level of a given skill
*
* @throws InvalidSkillException if the given skill is not valid
+ * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead
*/
+ @Deprecated
public static int getLevel(Player player, String skillType) {
return getPlayer(player).getSkillLevel(getSkillType(skillType));
}
+ /**
+ * Get the level a player has in a specific skill.
+ *
+ * This function is designed for API usage.
+ *
+ * @param player The player to get the level for
+ * @param skillType The skill to get the level for
+ * @return the level of a given skill
+ *
+ * @throws InvalidSkillException if the given skill is not valid
+ */
+ public static int getLevel(Player player, PrimarySkillType skillType) {
+ return getPlayer(player).getSkillLevel(skillType);
+ }
+
/**
* Get the level an offline player has in a specific skill.
*
@@ -995,7 +1012,7 @@ public final class ExperienceAPI {
* @throws InvalidFormulaTypeException if the given formulaType is not valid
*/
public static int getXpNeededToLevel(int level) {
- return mcMMO.getFormulaManager().getCachedXpToLevel(level, ExperienceConfig.getInstance().getFormulaType());
+ return mcMMO.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType());
}
/**
@@ -1009,7 +1026,7 @@ public final class ExperienceAPI {
* @throws InvalidFormulaTypeException if the given formulaType is not valid
*/
public static int getXpNeededToLevel(int level, String formulaType) {
- return mcMMO.getFormulaManager().getCachedXpToLevel(level, getFormulaType(formulaType));
+ return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType));
}
/**
diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java
index f30d8b0a1..6629adc2d 100644
--- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java
+++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java
@@ -203,7 +203,7 @@ public class Party {
public int getXpToLevel() {
FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
- return (mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType)) * (getOnlineMembers().size() + Config.getInstance().getPartyXpCurveMultiplier());
+ return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + Config.getInstance().getPartyXpCurveMultiplier());
}
public String getXpToLevelPercentage() {
diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java
index f71ceeca1..b2b0f7803 100644
--- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java
+++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java
@@ -397,7 +397,7 @@ public class PlayerProfile {
int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType);
FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
- return mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType);
+ return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType);
}
private int getChildSkillLevel(PrimarySkillType primarySkillType) {
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 85f29d893..c756017bf 100644
--- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java
+++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java
@@ -66,7 +66,7 @@ public enum PrimarySkillType {
ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER));
private Class extends SkillManager> managerClass;
- private Color runescapeColor;
+ private Color skillColor;
private SuperAbilityType ability;
private ToolType tool;
private List subSkillTypes;
@@ -110,13 +110,13 @@ public enum PrimarySkillType {
NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills);
}
- private PrimarySkillType(Class extends SkillManager> managerClass, Color runescapeColor, List subSkillTypes) {
- this(managerClass, runescapeColor, null, null, subSkillTypes);
+ private PrimarySkillType(Class extends SkillManager> managerClass, Color skillColor, List subSkillTypes) {
+ this(managerClass, skillColor, null, null, subSkillTypes);
}
- private PrimarySkillType(Class extends SkillManager> managerClass, Color runescapeColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) {
+ private PrimarySkillType(Class extends SkillManager> managerClass, Color skillColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) {
this.managerClass = managerClass;
- this.runescapeColor = runescapeColor;
+ this.skillColor = skillColor;
this.ability = ability;
this.tool = tool;
this.subSkillTypes = subSkillTypes;
@@ -243,7 +243,7 @@ public enum PrimarySkillType {
}
/* public void celebrateLevelUp(Player player) {
- ParticleEffectUtils.fireworkParticleShower(player, runescapeColor);
+ ParticleEffectUtils.fireworkParticleShower(player, skillColor);
}*/
public boolean shouldProcess(Entity target) {
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 ad2145f05..5d770be6d 100644
--- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java
+++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java
@@ -15,8 +15,10 @@ public class FormulaManager {
private static File formulaFile = new File(mcMMO.getFlatFileDirectory() + "formula.yml");
// Experience needed to reach a level, cached values to improve conversion speed
- private final Map experienceNeededLinear = new HashMap();
- private final Map experienceNeededExponential = new HashMap();
+ private Map experienceNeededRetroLinear;
+ private Map experienceNeededStandardLinear;
+ private Map experienceNeededRetroExponential;
+ private Map experienceNeededStandardExponential;
private FormulaType previousFormula;
@@ -26,9 +28,20 @@ public class FormulaManager {
public FormulaManager() {
/* Setting for Classic Mode (Scales a lot of stuff up by * 10) */
retroModeEnabled = Config.getInstance().getIsRetroMode();
+ initExperienceNeededMaps();
loadFormula();
}
+ /**
+ * Initialize maps used for XP to next level
+ */
+ private void initExperienceNeededMaps() {
+ experienceNeededRetroLinear = new HashMap<>();
+ experienceNeededRetroExponential = new HashMap<>();
+ experienceNeededStandardLinear = new HashMap<>();
+ experienceNeededStandardExponential = new HashMap<>();
+ }
+
/**
* Get the formula type that was used before converting
*
@@ -60,7 +73,7 @@ public class FormulaManager {
int totalXP = 0;
for (int level = 0; level < skillLevel; level++) {
- totalXP += getCachedXpToLevel(level, previousFormula);
+ totalXP += getXPtoNextLevel(level, previousFormula);
}
totalXP += skillXPLevel;
@@ -83,7 +96,7 @@ public class FormulaManager {
int maxLevel = Config.getInstance().getLevelCap(primarySkillType);
while (experience > 0 && newLevel < maxLevel) {
- int experienceToNextLevel = getCachedXpToLevel(newLevel, formulaType);
+ int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType);
if (experience - experienceToNextLevel < 0) {
remainder = experience;
@@ -106,42 +119,97 @@ public class FormulaManager {
* @param formulaType The {@link FormulaType} used
* @return amount of experience needed to reach next level
*/
- public int getCachedXpToLevel(int level, FormulaType formulaType) {
- int experience;
-
+ public int getXPtoNextLevel(int level, FormulaType formulaType) {
/**
* Retro mode XP requirements are the default requirements
* Standard mode XP requirements are multiplied by a factor of 10
*/
- int xpNeededMultiplier = retroModeEnabled ? 1 : 10;
+ //TODO: When the heck is Unknown used?
if (formulaType == FormulaType.UNKNOWN) {
formulaType = FormulaType.LINEAR;
}
+ return processXPToNextLevel(level, formulaType);
+ }
+
+ /**
+ * Gets the value of XP needed for the next level based on the level Scaling, the level, and the formula type
+ * @param level target level
+ * @param formulaType target formulaType
+ */
+ private int processXPToNextLevel(int level, FormulaType formulaType) {
+ if(mcMMO.isRetroModeEnabled())
+ {
+ return processXPRetroToNextLevel(level, formulaType);
+ } else {
+ return processStandardXPToNextLevel(level, formulaType);
+ }
+ }
+
+ /**
+ * Calculate the XP needed for the next level for the linear formula for Standard scaling (1-100)
+ * @param level target level
+ * @return raw xp needed to reach the next level
+ */
+ private int processStandardXPToNextLevel(int level, FormulaType formulaType) {
+ Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededStandardLinear : experienceNeededStandardExponential;
+
+ if(!experienceMapRef.containsKey(level)) {
+ int experienceSum = 0;
+ int retroIndex = (level * 10) + 1;
+
+ //Sum the range of levels in Retro that this Standard level would represent
+ for(int x = retroIndex; x < (retroIndex + 10); x++) {
+ //calculateXPNeeded doesn't cache results so we use that instead of invoking the Retro XP methods to avoid memory bloat
+ experienceSum += calculateXPNeeded(x, formulaType);
+ }
+
+ experienceMapRef.put(level, experienceSum);
+ }
+
+ return experienceMapRef.get(level);
+ }
+
+ /**
+ * Calculates the XP to next level for Retro Mode scaling
+ * Results are cached to reduce needless operations
+ * @param level target level
+ * @param formulaType target formula type
+ * @return raw xp needed to reach the next level based on formula type
+ */
+ private int processXPRetroToNextLevel(int level, FormulaType formulaType) {
+ Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededRetroLinear : experienceNeededRetroExponential;
+
+ if (!experienceMapRef.containsKey(level)) {
+ int experience = calculateXPNeeded(level, FormulaType.LINEAR);
+ experienceMapRef.put(level, experience);
+ }
+
+ return experienceMapRef.get(level);
+ }
+
+ /**
+ * Does the actual math to get the XP needed for a level in RetroMode scaling
+ * Standard uses a sum of RetroMode XP needed levels for its own thing, so it uses this too
+ * @param level target level
+ * @param formulaType target formulatype
+ * @return the raw XP needed for the next level based on formula type
+ */
+ private int calculateXPNeeded(int level, FormulaType formulaType) {
int base = ExperienceConfig.getInstance().getBase(formulaType);
double multiplier = ExperienceConfig.getInstance().getMultiplier(formulaType);
- double exponent = ExperienceConfig.getInstance().getExponent(formulaType);
- switch (formulaType) {
+ switch(formulaType) {
case LINEAR:
- if (!experienceNeededLinear.containsKey(level)) {
- experience = (int) Math.floor( xpNeededMultiplier * (base + level * multiplier));
- experienceNeededLinear.put(level, experience);
- }
-
- return experienceNeededLinear.get(level);
-
+ return (int) Math.floor(base + level * multiplier);
case EXPONENTIAL:
- if (!experienceNeededExponential.containsKey(level)) {
- experience = (int) Math.floor( xpNeededMultiplier * (multiplier * Math.pow(level, exponent) + base));
- experienceNeededExponential.put(level, experience);
- }
-
- return experienceNeededExponential.get(level);
-
+ double exponent = ExperienceConfig.getInstance().getExponent(formulaType);
+ return (int) Math.floor(multiplier * Math.pow(level, exponent) + base);
default:
- return 0;
+ //TODO: Should never be called
+ mcMMO.p.getLogger().severe("Invalid formula specified for calculation, defaulting to Linear");
+ return calculateXPNeeded(level, FormulaType.LINEAR);
}
}