From 8026785f16c817ece70e4323dd5289baa678d4aa Mon Sep 17 00:00:00 2001 From: emerald000 Date: Mon, 20 May 2019 10:31:16 -0400 Subject: [PATCH] Refactor combat level calculations to use closed-form formulas. (#8874) * Refactor combat level calculations to use closed-form formulas. Also move most calculations to the Experience utility class. Fixes #7411. * Add new test for magic levels that barely reach the next combat level. * Add another test that breaks on master. --- .../java/net/runelite/api/Experience.java | 117 ++++- .../combatlevel/CombatLevelOverlay.java | 103 +--- .../combatlevel/CombatLevelPluginTest.java | 462 ++++++++++-------- 3 files changed, 396 insertions(+), 286 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Experience.java b/runelite-api/src/main/java/net/runelite/api/Experience.java index 088a88d544..d83a61c97b 100644 --- a/runelite-api/src/main/java/net/runelite/api/Experience.java +++ b/runelite-api/src/main/java/net/runelite/api/Experience.java @@ -24,9 +24,6 @@ */ package net.runelite.api; -import static java.lang.Math.floor; -import static java.lang.Math.max; - /** * A utility class used for calculating experience related values. *

@@ -127,6 +124,15 @@ public class Experience return high + 1; } + private static double getMeleeRangeOrMagicCombatLevelContribution(int attackLevel, int strengthLevel, int magicLevel, int rangeLevel) + { + double melee = 0.325 * (attackLevel + strengthLevel); + double range = 0.325 * (Math.floor(rangeLevel / 2) + rangeLevel); + double magic = 0.325 * (Math.floor(magicLevel / 2) + magicLevel); + + return Math.max(melee, Math.max(range, magic)); + } + /** * Calculates a non-virtual high-precision combat level without integer * rounding. @@ -146,13 +152,11 @@ public class Experience int defenceLevel, int hitpointsLevel, int magicLevel, int rangeLevel, int prayerLevel) { - double base = 0.25 * (defenceLevel + hitpointsLevel + floor(prayerLevel / 2)); + double base = 0.25 * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); - double melee = 0.325 * (attackLevel + strengthLevel); - double range = 0.325 * (floor(rangeLevel / 2) + rangeLevel); - double magic = 0.325 * (floor(magicLevel / 2) + magicLevel); + double typeContribution = getMeleeRangeOrMagicCombatLevelContribution(attackLevel, strengthLevel, magicLevel, rangeLevel); - return base + max(melee, max(range, magic)); + return base + typeContribution; } /** @@ -173,4 +177,101 @@ public class Experience { return (int) getCombatLevelPrecise(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel); } + + /** + * Calculate number of attack/strength levels required to increase combat level. + * + * @param attackLevel the attack level + * @param strengthLevel the strength level + * @param defenceLevel the defence level + * @param hitpointsLevel the hitpoints level + * @param magicLevel the magic level + * @param rangeLevel the range level + * @param prayerLevel the prayer level + * @return the number of levels required + */ + public static int getNextCombatLevelMelee(int attackLevel, int strengthLevel, int defenceLevel, int hitpointsLevel, + int magicLevel, int rangeLevel, int prayerLevel) + { + int nextCombatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel) + 1; + return (int) Math.ceil(-10. / 13 * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2) - 4 * nextCombatLevel)) - strengthLevel - attackLevel; + } + + /** + * Calculate number of hitpoints/defence levels required to increase combat level. + * + * @param attackLevel the attack level + * @param strengthLevel the strength level + * @param defenceLevel the defence level + * @param hitpointsLevel the hitpoints level + * @param magicLevel the magic level + * @param rangeLevel the range level + * @param prayerLevel the prayer level + * @return the number of levels required + */ + public static int getNextCombatLevelHpDef(int attackLevel, int strengthLevel, int defenceLevel, int hitpointsLevel, + int magicLevel, int rangeLevel, int prayerLevel) + { + int nextCombatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel) + 1; + double typeContribution = Experience.getMeleeRangeOrMagicCombatLevelContribution(attackLevel, strengthLevel, magicLevel, rangeLevel); + return (int) Math.ceil(4 * nextCombatLevel - Math.floor(prayerLevel / 2) - 4 * typeContribution) - hitpointsLevel - defenceLevel; + } + + /** + * Calculate number of magic levels required to increase combat level. + * + * @param attackLevel the attack level + * @param strengthLevel the strength level + * @param defenceLevel the defence level + * @param hitpointsLevel the hitpoints level + * @param magicLevel the magic level + * @param rangeLevel the range level + * @param prayerLevel the prayer level + * @return the number of levels required + */ + public static int getNextCombatLevelMagic(int attackLevel, int strengthLevel, int defenceLevel, int hitpointsLevel, + int magicLevel, int rangeLevel, int prayerLevel) + { + int nextCombatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel) + 1; + return (int) Math.ceil(2. / 3 * Math.ceil(-10. / 13 * (hitpointsLevel + defenceLevel - 4 * nextCombatLevel + Math.floor(prayerLevel / 2)))) - magicLevel; + } + + /** + * Calculate number of ranged levels required to increase combat level. + * + * @param attackLevel the attack level + * @param strengthLevel the strength level + * @param defenceLevel the defence level + * @param hitpointsLevel the hitpoints level + * @param magicLevel the magic level + * @param rangeLevel the range level + * @param prayerLevel the prayer level + * @return the number of levels required + */ + public static int getNextCombatLevelRange(int attackLevel, int strengthLevel, int defenceLevel, int hitpointsLevel, + int magicLevel, int rangeLevel, int prayerLevel) + { + int nextCombatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel) + 1; + return (int) Math.ceil(2. / 3 * Math.ceil(-10. / 13 * (hitpointsLevel + defenceLevel - 4 * nextCombatLevel + Math.floor(prayerLevel / 2)))) - rangeLevel; + } + + /** + * Calculate number of prayer levels required to increase combat level. + * + * @param attackLevel the attack level + * @param strengthLevel the strength level + * @param defenceLevel the defence level + * @param hitpointsLevel the hitpoints level + * @param magicLevel the magic level + * @param rangeLevel the range level + * @param prayerLevel the prayer level + * @return the number of levels required + */ + public static int getNextCombatLevelPrayer(int attackLevel, int strengthLevel, int defenceLevel, int hitpointsLevel, + int magicLevel, int rangeLevel, int prayerLevel) + { + int nextCombatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, magicLevel, rangeLevel, prayerLevel) + 1; + double typeContribution = Experience.getMeleeRangeOrMagicCombatLevelContribution(attackLevel, strengthLevel, magicLevel, rangeLevel); + return 2 * (int) Math.ceil(-hitpointsLevel - defenceLevel + 4 * nextCombatLevel - 4 * typeContribution) - prayerLevel; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java index 6e81a7a983..01586b9e2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java @@ -24,7 +24,6 @@ */ package net.runelite.client.plugins.combatlevel; -import com.google.common.annotations.VisibleForTesting; import net.runelite.api.Client; import net.runelite.api.Experience; import net.runelite.api.Skill; @@ -43,11 +42,6 @@ import java.awt.Rectangle; class CombatLevelOverlay extends Overlay { private static final Color COMBAT_LEVEL_COLOUR = new Color(0xff981f); - private static final double PRAY_MULT = 0.125; - static final double ATT_STR_MULT = 0.325; - static final double DEF_HP_MULT = 0.25; - static final double RANGE_MAGIC_LEVEL_MULT = 1.5; - static final double RANGE_MAGIC_MULT = 0.325; private final Client client; private final CombatLevelConfig config; @@ -95,23 +89,20 @@ class CombatLevelOverlay extends Overlay int defenceLevel = client.getRealSkillLevel(Skill.DEFENCE); int hitpointsLevel = client.getRealSkillLevel(Skill.HITPOINTS); int magicLevel = client.getRealSkillLevel(Skill.MAGIC); - int rangedLevel = client.getRealSkillLevel(Skill.RANGED); + int rangeLevel = client.getRealSkillLevel(Skill.RANGED); int prayerLevel = client.getRealSkillLevel(Skill.PRAYER); - // calculate initial required numbers - double base = DEF_HP_MULT * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); - double melee = ATT_STR_MULT * (attackLevel + strengthLevel); - double range = RANGE_MAGIC_MULT * Math.floor(rangedLevel * RANGE_MAGIC_LEVEL_MULT); - double mage = RANGE_MAGIC_MULT * Math.floor(magicLevel * RANGE_MAGIC_LEVEL_MULT); - double max = Math.max(melee, Math.max(range, mage)); - // find the needed levels until level up - int next = client.getLocalPlayer().getCombatLevel() + 1; - int meleeNeed = calcLevels(base + melee, next, ATT_STR_MULT); - int hpdefNeed = calcLevels(base + max, next, DEF_HP_MULT); - int prayNeed = calcLevelsPray(base + max, next, prayerLevel); - int rangeNeed = calcLevelsRM(rangedLevel, next, base); - int magicNeed = calcLevelsRM(magicLevel, next, base); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); // create tooltip string StringBuilder sb = new StringBuilder(); @@ -121,11 +112,11 @@ class CombatLevelOverlay extends Overlay { sb.append(meleeNeed).append(" Attack/Strength
"); } - if ((hitpointsLevel + defenceLevel + hpdefNeed) <= Experience.MAX_REAL_LEVEL * 2) + if ((hitpointsLevel + defenceLevel + hpDefNeed) <= Experience.MAX_REAL_LEVEL * 2) { - sb.append(hpdefNeed).append(" Defence/Hitpoints
"); + sb.append(hpDefNeed).append(" Defence/Hitpoints
"); } - if ((rangedLevel + rangeNeed) <= Experience.MAX_REAL_LEVEL) + if ((rangeLevel + rangeNeed) <= Experience.MAX_REAL_LEVEL) { sb.append(rangeNeed).append(" Ranged
"); } @@ -133,73 +124,11 @@ class CombatLevelOverlay extends Overlay { sb.append(magicNeed).append(" Magic
"); } - if ((prayerLevel + prayNeed) <= Experience.MAX_REAL_LEVEL) + if ((prayerLevel + prayerNeed) <= Experience.MAX_REAL_LEVEL) { - sb.append(prayNeed).append(" Prayer"); + sb.append(prayerNeed).append(" Prayer"); } return sb.toString(); } - /** - * Calculate skill levels required for increasing combat level, meant - * for all combat skills besides prayer, ranged, and magic. - * @param start initial value - * @param end ending value (combat level + 1) - * @param multiple how much adding one skill level will change combat - * @return levels required for a specific skill to level up combat - */ - @VisibleForTesting - static int calcLevels(double start, int end, double multiple) - { - return (int) Math.ceil(calcMultipliedLevels(start, end, multiple)); - } - - /** - * Calculate skill levels for increasing combat level, meant ONLY for the Prayer skill. - *

- * Note: Prayer is a special case, only leveling up upon even level numbers. This is accounted - * for in this function. - *

- * @param start current combat level - * @param end ending value (combat level + 1) - * @param prayerLevel the player's current prayer level - * @return Prayer levels required to level up combat - */ - @VisibleForTesting - static int calcLevelsPray(double start, int end, int prayerLevel) - { - int neededLevels = (int) Math.ceil(calcMultipliedLevels(start, end, PRAY_MULT)); - - if (prayerLevel % 2 != 0) - { - neededLevels--; - } - - if ((prayerLevel + neededLevels) % 2 != 0) - { - return neededLevels + 1; - } - - return neededLevels; - } - - private static double calcMultipliedLevels(double start, int end, double multiple) - { - return (end - start) / multiple; - } - - /** - * Calculate skill levels required for increasing combat level, meant - * ONLY for Ranged and Magic skills. - * @param start either the current ranged or magic level - * @param end ending value (combat level + 1) - * @param dhp defence, hitpoints, and prayer; this is the initial calculated "base" value - * @return levels required for a specific skill to level up combat - */ - @VisibleForTesting - static int calcLevelsRM(double start, int end, double dhp) - { - start = Math.floor(start * RANGE_MAGIC_LEVEL_MULT) * RANGE_MAGIC_MULT; - return (int) Math.ceil((end - dhp - start) / (RANGE_MAGIC_MULT * RANGE_MAGIC_LEVEL_MULT)); - } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/combatlevel/CombatLevelPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/combatlevel/CombatLevelPluginTest.java index 361fa04aea..e372ef763f 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/combatlevel/CombatLevelPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/combatlevel/CombatLevelPluginTest.java @@ -24,209 +24,184 @@ */ package net.runelite.client.plugins.combatlevel; -import com.google.inject.Guice; -import com.google.inject.testing.fieldbinder.Bind; -import com.google.inject.testing.fieldbinder.BoundFieldModule; -import net.runelite.api.Client; -import net.runelite.api.Player; -import net.runelite.api.Skill; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.calcLevels; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.calcLevelsPray; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.calcLevelsRM; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.ATT_STR_MULT; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.DEF_HP_MULT; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.RANGE_MAGIC_LEVEL_MULT; -import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.RANGE_MAGIC_MULT; +import net.runelite.api.Experience; import static org.junit.Assert.assertEquals; -import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import static org.mockito.Mockito.when; -import org.mockito.runners.MockitoJUnitRunner; -import java.util.HashMap; -@RunWith(MockitoJUnitRunner.class) public class CombatLevelPluginTest { - @Mock - @Bind - private Client client; - - @Mock - private Player player; - - @Before - public void setUp() - { - Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); - - when(client.getLocalPlayer()).thenReturn(player); - } - - private HashMap getBaseValues() - { - int attackLevel = client.getRealSkillLevel(Skill.ATTACK); - int strengthLevel = client.getRealSkillLevel(Skill.STRENGTH); - int defenceLevel = client.getRealSkillLevel(Skill.DEFENCE); - int hitpointsLevel = client.getRealSkillLevel(Skill.HITPOINTS); - int magicLevel = client.getRealSkillLevel(Skill.MAGIC); - int rangedLevel = client.getRealSkillLevel(Skill.RANGED); - int prayerLevel = client.getRealSkillLevel(Skill.PRAYER); - - double base = DEF_HP_MULT * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); - double melee = ATT_STR_MULT * (attackLevel + strengthLevel); - double range = RANGE_MAGIC_MULT * Math.floor(rangedLevel * RANGE_MAGIC_LEVEL_MULT); - double mage = RANGE_MAGIC_MULT * Math.floor(magicLevel * RANGE_MAGIC_LEVEL_MULT); - double max = Math.max(melee, Math.max(range, mage)); - - HashMap result = new HashMap<>(); - result.put("base", base); - result.put("melee", melee); - result.put("max", max); - return result; - } - @Test public void testNewPlayer() { - when(player.getCombatLevel()).thenReturn(3); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(1); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(1); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(1); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(1); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(1); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(1); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(10); + int attackLevel = 1; + int strengthLevel = 1; + int defenceLevel = 1; + int hitpointsLevel = 10; + int magicLevel = 1; + int rangeLevel = 1; + int prayerLevel = 1; - HashMap baseValues = getBaseValues(); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(3, combatLevel); // test attack/strength - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), - player.getCombatLevel() + 1, ATT_STR_MULT)); + assertEquals(2, meleeNeed); // test defence/hitpoints - assertEquals(3, calcLevels(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, DEF_HP_MULT)); - - // test prayer - assertEquals(5, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER))); + assertEquals(3, hpDefNeed); // test ranged - assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(2, rangeNeed); // test magic - assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(2, magicNeed); + + // test prayer + assertEquals(5, prayerNeed); } @Test public void testAll10() { - when(player.getCombatLevel()).thenReturn(12); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(10); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(10); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(10); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(10); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(10); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(10); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(10); + int attackLevel = 10; + int strengthLevel = 10; + int defenceLevel = 10; + int hitpointsLevel = 10; + int magicLevel = 10; + int rangeLevel = 10; + int prayerLevel = 10; - HashMap baseValues = getBaseValues(); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(12, combatLevel); // test attack/strength - assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("melee"), - player.getCombatLevel() + 1, ATT_STR_MULT)); + assertEquals(1, meleeNeed); // test defence/hitpoints - assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, DEF_HP_MULT)); - - // test prayer - assertEquals(2, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER))); + assertEquals(1, hpDefNeed); // test ranged - assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(4, rangeNeed); // test magic - assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(4, magicNeed); + + // test prayer + assertEquals(2, prayerNeed); } @Test public void testPlayerBmid() { // snapshot of current stats 2018-10-2 - when(player.getCombatLevel()).thenReturn(83); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(65); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(70); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(60); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(56); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(75); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(73); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(71); + int attackLevel = 65; + int strengthLevel = 70; + int defenceLevel = 60; + int hitpointsLevel = 71; + int magicLevel = 73; + int rangeLevel = 75; + int prayerLevel = 56; - HashMap baseValues = getBaseValues(); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(83, combatLevel); // test attack/strength - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), - player.getCombatLevel() + 1, ATT_STR_MULT)); + assertEquals(2, meleeNeed); // test defence/hitpoints - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, DEF_HP_MULT)); - - // test prayer - assertEquals(4, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER))); + assertEquals(2, hpDefNeed); // test ranged - assertEquals(17, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(17, rangeNeed); // test magic - assertEquals(19, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(19, magicNeed); + + // test prayer + assertEquals(4, prayerNeed); } @Test public void testPlayerRunelite() { // snapshot of current stats 2018-10-2 - when(player.getCombatLevel()).thenReturn(43); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(43); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(36); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(1); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(15); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(51); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(64); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(42); + int attackLevel = 43; + int strengthLevel = 36; + int defenceLevel = 1; + int hitpointsLevel = 42; + int magicLevel = 64; + int rangeLevel = 51; + int prayerLevel = 15; - HashMap baseValues = getBaseValues(); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(43, combatLevel); // test attack/strength - assertEquals(18, calcLevels(baseValues.get("base") + baseValues.get("melee"), - player.getCombatLevel() + 1, ATT_STR_MULT)); + assertEquals(18, meleeNeed); // test defence/hitpoints - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, DEF_HP_MULT)); - - // test prayer - assertEquals(3, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER))); + assertEquals(2, hpDefNeed); // test ranged - assertEquals(14, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(14, rangeNeed); // test magic - assertEquals(1, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), - player.getCombatLevel() + 1, baseValues.get("base"))); + assertEquals(1, magicNeed); + + // test prayer + assertEquals(3, prayerNeed); } @Test @@ -234,83 +209,188 @@ public class CombatLevelPluginTest { // snapshot of current stats 2018-10-3 // Zezima cannot earn a combat level from ranged/magic anymore, so it won't show as the result is too high - when(player.getCombatLevel()).thenReturn(90); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(74); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(52); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72); + int attackLevel = 74; + int strengthLevel = 74; + int defenceLevel = 72; + int hitpointsLevel = 72; + int magicLevel = 60; + int rangeLevel = 44; + int prayerLevel = 52; - HashMap baseValues = getBaseValues(); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(90, combatLevel); // test attack/strength - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), - player.getCombatLevel() + 1, ATT_STR_MULT)); + assertEquals(2, meleeNeed); // test defence/hitpoints - assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, DEF_HP_MULT)); + assertEquals(2, hpDefNeed); // test prayer - assertEquals(4, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER))); + assertEquals(4, prayerNeed); } @Test public void testPrayerLevelsNeeded() { - when(player.getCombatLevel()).thenReturn(124); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(99); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(99); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(99); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(89); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(99); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(99); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(99); + int attackLevel = 99; + int strengthLevel = 99; + int defenceLevel = 99; + int hitpointsLevel = 99; + int magicLevel = 99; + int rangeLevel = 99; + int prayerLevel = 89; - assertEquals(1, neededPrayerLevels()); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(124, combatLevel); + + // test prayer + assertEquals(1, prayerNeed); } @Test public void testEvenPrayerLevelsNeededWhenNearNextCombatLevel() { - when(player.getCombatLevel()).thenReturn(90); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(75); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(52); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72); + int attackLevel = 74; + int strengthLevel = 75; + int defenceLevel = 72; + int hitpointsLevel = 72; + int magicLevel = 60; + int rangeLevel = 44; + int prayerLevel = 52; - assertEquals(2, neededPrayerLevels()); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(90, combatLevel); + + // test prayer + assertEquals(2, prayerNeed); } @Test public void testOddPrayerLevelsNeededWhenNearNextCombatLevel() { - when(player.getCombatLevel()).thenReturn(90); - when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); - when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(75); - when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); - when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(53); - when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); - when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); - when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72); + int attackLevel = 74; + int strengthLevel = 75; + int defenceLevel = 72; + int hitpointsLevel = 72; + int magicLevel = 60; + int rangeLevel = 44; + int prayerLevel = 53; - assertEquals(1, neededPrayerLevels()); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(90, combatLevel); + + // test prayer + assertEquals(1, prayerNeed); } - private int neededPrayerLevels() + @Test + public void testNextMagicLevelBarelyReachesNextCombatLevel() { - HashMap baseValues = getBaseValues(); + int attackLevel = 40; + int strengthLevel = 44; + int defenceLevel = 46; + int hitpointsLevel = 39; + int magicLevel = 57; + int rangeLevel = 40; + int prayerLevel = 29; - return calcLevelsPray( - baseValues.get("base") + baseValues.get("max"), - player.getCombatLevel() + 1, - client.getRealSkillLevel(Skill.PRAYER) - ); + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(52, combatLevel); + + // test attack/strength + assertEquals(3, meleeNeed); + + // test defence/hitpoints + assertEquals(3, hpDefNeed); + + // test ranged + assertEquals(18, rangeNeed); + + // test magic + assertEquals(1, magicNeed); + + // test prayer + assertEquals(5, prayerNeed); + } + + @Test + public void testRangeMagicLevelsNeeded() + { + int attackLevel = 60; + int strengthLevel = 69; + int defenceLevel = 1; + int hitpointsLevel = 78; + int magicLevel = 85; + int rangeLevel = 85; + int prayerLevel = 52; + + int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int magicNeed = Experience.getNextCombatLevelMagic(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + int prayerNeed = Experience.getNextCombatLevelPrayer(attackLevel, strengthLevel, defenceLevel, hitpointsLevel, + magicLevel, rangeLevel, prayerLevel); + + // test combat level + assertEquals(68, combatLevel); + + // test attack/strength + assertEquals(3, meleeNeed); + + // test defence/hitpoints + assertEquals(4, hpDefNeed); + + // test ranged + assertEquals(3, rangeNeed); + + // test magic + assertEquals(3, magicNeed); + + // test prayer + assertEquals(8, prayerNeed); } }