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.
This commit is contained in:
emerald000
2019-05-20 10:31:16 -04:00
committed by Adam
parent 8890d5b634
commit 8026785f16
3 changed files with 396 additions and 286 deletions

View File

@@ -24,9 +24,6 @@
*/ */
package net.runelite.api; 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. * A utility class used for calculating experience related values.
* <p> * <p>
@@ -127,6 +124,15 @@ public class Experience
return high + 1; 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 * Calculates a non-virtual high-precision combat level without integer
* rounding. * rounding.
@@ -146,13 +152,11 @@ public class Experience
int defenceLevel, int hitpointsLevel, int magicLevel, int defenceLevel, int hitpointsLevel, int magicLevel,
int rangeLevel, int prayerLevel) 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 typeContribution = getMeleeRangeOrMagicCombatLevelContribution(attackLevel, strengthLevel, magicLevel, rangeLevel);
double range = 0.325 * (floor(rangeLevel / 2) + rangeLevel);
double magic = 0.325 * (floor(magicLevel / 2) + magicLevel);
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); 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;
}
} }

View File

@@ -24,7 +24,6 @@
*/ */
package net.runelite.client.plugins.combatlevel; package net.runelite.client.plugins.combatlevel;
import com.google.common.annotations.VisibleForTesting;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Experience; import net.runelite.api.Experience;
import net.runelite.api.Skill; import net.runelite.api.Skill;
@@ -43,11 +42,6 @@ import java.awt.Rectangle;
class CombatLevelOverlay extends Overlay class CombatLevelOverlay extends Overlay
{ {
private static final Color COMBAT_LEVEL_COLOUR = new Color(0xff981f); 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 Client client;
private final CombatLevelConfig config; private final CombatLevelConfig config;
@@ -95,23 +89,20 @@ class CombatLevelOverlay extends Overlay
int defenceLevel = client.getRealSkillLevel(Skill.DEFENCE); int defenceLevel = client.getRealSkillLevel(Skill.DEFENCE);
int hitpointsLevel = client.getRealSkillLevel(Skill.HITPOINTS); int hitpointsLevel = client.getRealSkillLevel(Skill.HITPOINTS);
int magicLevel = client.getRealSkillLevel(Skill.MAGIC); int magicLevel = client.getRealSkillLevel(Skill.MAGIC);
int rangedLevel = client.getRealSkillLevel(Skill.RANGED); int rangeLevel = client.getRealSkillLevel(Skill.RANGED);
int prayerLevel = client.getRealSkillLevel(Skill.PRAYER); 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 // find the needed levels until level up
int next = client.getLocalPlayer().getCombatLevel() + 1; int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel,
int meleeNeed = calcLevels(base + melee, next, ATT_STR_MULT); magicLevel, rangeLevel, prayerLevel);
int hpdefNeed = calcLevels(base + max, next, DEF_HP_MULT); int hpDefNeed = Experience.getNextCombatLevelHpDef(attackLevel, strengthLevel, defenceLevel, hitpointsLevel,
int prayNeed = calcLevelsPray(base + max, next, prayerLevel); magicLevel, rangeLevel, prayerLevel);
int rangeNeed = calcLevelsRM(rangedLevel, next, base); int rangeNeed = Experience.getNextCombatLevelRange(attackLevel, strengthLevel, defenceLevel, hitpointsLevel,
int magicNeed = calcLevelsRM(magicLevel, next, base); 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 // create tooltip string
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -121,11 +112,11 @@ class CombatLevelOverlay extends Overlay
{ {
sb.append(meleeNeed).append(" Attack/Strength</br>"); sb.append(meleeNeed).append(" Attack/Strength</br>");
} }
if ((hitpointsLevel + defenceLevel + hpdefNeed) <= Experience.MAX_REAL_LEVEL * 2) if ((hitpointsLevel + defenceLevel + hpDefNeed) <= Experience.MAX_REAL_LEVEL * 2)
{ {
sb.append(hpdefNeed).append(" Defence/Hitpoints</br>"); sb.append(hpDefNeed).append(" Defence/Hitpoints</br>");
} }
if ((rangedLevel + rangeNeed) <= Experience.MAX_REAL_LEVEL) if ((rangeLevel + rangeNeed) <= Experience.MAX_REAL_LEVEL)
{ {
sb.append(rangeNeed).append(" Ranged</br>"); sb.append(rangeNeed).append(" Ranged</br>");
} }
@@ -133,73 +124,11 @@ class CombatLevelOverlay extends Overlay
{ {
sb.append(magicNeed).append(" Magic</br>"); sb.append(magicNeed).append(" Magic</br>");
} }
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(); 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.
* <p>
* Note: Prayer is a special case, only leveling up upon even level numbers. This is accounted
* for in this function.
* </p>
* @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));
}
} }

View File

@@ -24,209 +24,184 @@
*/ */
package net.runelite.client.plugins.combatlevel; package net.runelite.client.plugins.combatlevel;
import com.google.inject.Guice; import net.runelite.api.Experience;
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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test; 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 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<String, Double> 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<String, Double> result = new HashMap<>();
result.put("base", base);
result.put("melee", melee);
result.put("max", max);
return result;
}
@Test @Test
public void testNewPlayer() public void testNewPlayer()
{ {
when(player.getCombatLevel()).thenReturn(3); int attackLevel = 1;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(1); int strengthLevel = 1;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(1); int defenceLevel = 1;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(1); int hitpointsLevel = 10;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(1); int magicLevel = 1;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(1); int rangeLevel = 1;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(1); int prayerLevel = 1;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(10);
HashMap<String, Double> 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 // test attack/strength
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), assertEquals(2, meleeNeed);
player.getCombatLevel() + 1, ATT_STR_MULT));
// test defence/hitpoints // test defence/hitpoints
assertEquals(3, calcLevels(baseValues.get("base") + baseValues.get("max"), assertEquals(3, hpDefNeed);
player.getCombatLevel() + 1, DEF_HP_MULT));
// test prayer
assertEquals(5, calcLevelsPray(baseValues.get("base") + baseValues.get("max"),
player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER)));
// test ranged // test ranged
assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), assertEquals(2, rangeNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test magic // test magic
assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), assertEquals(2, magicNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test prayer
assertEquals(5, prayerNeed);
} }
@Test @Test
public void testAll10() public void testAll10()
{ {
when(player.getCombatLevel()).thenReturn(12); int attackLevel = 10;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(10); int strengthLevel = 10;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(10); int defenceLevel = 10;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(10); int hitpointsLevel = 10;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(10); int magicLevel = 10;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(10); int rangeLevel = 10;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(10); int prayerLevel = 10;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(10);
HashMap<String, Double> 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 // test attack/strength
assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("melee"), assertEquals(1, meleeNeed);
player.getCombatLevel() + 1, ATT_STR_MULT));
// test defence/hitpoints // test defence/hitpoints
assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("max"), assertEquals(1, hpDefNeed);
player.getCombatLevel() + 1, DEF_HP_MULT));
// test prayer
assertEquals(2, calcLevelsPray(baseValues.get("base") + baseValues.get("max"),
player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER)));
// test ranged // test ranged
assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), assertEquals(4, rangeNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test magic // test magic
assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), assertEquals(4, magicNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test prayer
assertEquals(2, prayerNeed);
} }
@Test @Test
public void testPlayerBmid() public void testPlayerBmid()
{ {
// snapshot of current stats 2018-10-2 // snapshot of current stats 2018-10-2
when(player.getCombatLevel()).thenReturn(83); int attackLevel = 65;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(65); int strengthLevel = 70;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(70); int defenceLevel = 60;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(60); int hitpointsLevel = 71;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(56); int magicLevel = 73;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(75); int rangeLevel = 75;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(73); int prayerLevel = 56;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(71);
HashMap<String, Double> 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 // test attack/strength
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), assertEquals(2, meleeNeed);
player.getCombatLevel() + 1, ATT_STR_MULT));
// test defence/hitpoints // test defence/hitpoints
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), assertEquals(2, hpDefNeed);
player.getCombatLevel() + 1, DEF_HP_MULT));
// test prayer
assertEquals(4, calcLevelsPray(baseValues.get("base") + baseValues.get("max"),
player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER)));
// test ranged // test ranged
assertEquals(17, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), assertEquals(17, rangeNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test magic // test magic
assertEquals(19, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), assertEquals(19, magicNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test prayer
assertEquals(4, prayerNeed);
} }
@Test @Test
public void testPlayerRunelite() public void testPlayerRunelite()
{ {
// snapshot of current stats 2018-10-2 // snapshot of current stats 2018-10-2
when(player.getCombatLevel()).thenReturn(43); int attackLevel = 43;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(43); int strengthLevel = 36;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(36); int defenceLevel = 1;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(1); int hitpointsLevel = 42;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(15); int magicLevel = 64;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(51); int rangeLevel = 51;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(64); int prayerLevel = 15;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(42);
HashMap<String, Double> 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 // test attack/strength
assertEquals(18, calcLevels(baseValues.get("base") + baseValues.get("melee"), assertEquals(18, meleeNeed);
player.getCombatLevel() + 1, ATT_STR_MULT));
// test defence/hitpoints // test defence/hitpoints
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), assertEquals(2, hpDefNeed);
player.getCombatLevel() + 1, DEF_HP_MULT));
// test prayer
assertEquals(3, calcLevelsPray(baseValues.get("base") + baseValues.get("max"),
player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER)));
// test ranged // test ranged
assertEquals(14, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), assertEquals(14, rangeNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test magic // test magic
assertEquals(1, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), assertEquals(1, magicNeed);
player.getCombatLevel() + 1, baseValues.get("base")));
// test prayer
assertEquals(3, prayerNeed);
} }
@Test @Test
@@ -234,83 +209,188 @@ public class CombatLevelPluginTest
{ {
// snapshot of current stats 2018-10-3 // 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 // 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); int attackLevel = 74;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); int strengthLevel = 74;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(74); int defenceLevel = 72;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); int hitpointsLevel = 72;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(52); int magicLevel = 60;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); int rangeLevel = 44;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); int prayerLevel = 52;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72);
HashMap<String, Double> 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 // test attack/strength
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), assertEquals(2, meleeNeed);
player.getCombatLevel() + 1, ATT_STR_MULT));
// test defence/hitpoints // test defence/hitpoints
assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), assertEquals(2, hpDefNeed);
player.getCombatLevel() + 1, DEF_HP_MULT));
// test prayer // test prayer
assertEquals(4, calcLevelsPray(baseValues.get("base") + baseValues.get("max"), assertEquals(4, prayerNeed);
player.getCombatLevel() + 1, client.getRealSkillLevel(Skill.PRAYER)));
} }
@Test @Test
public void testPrayerLevelsNeeded() public void testPrayerLevelsNeeded()
{ {
when(player.getCombatLevel()).thenReturn(124); int attackLevel = 99;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(99); int strengthLevel = 99;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(99); int defenceLevel = 99;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(99); int hitpointsLevel = 99;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(89); int magicLevel = 99;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(99); int rangeLevel = 99;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(99); int prayerLevel = 89;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(99);
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 @Test
public void testEvenPrayerLevelsNeededWhenNearNextCombatLevel() public void testEvenPrayerLevelsNeededWhenNearNextCombatLevel()
{ {
when(player.getCombatLevel()).thenReturn(90); int attackLevel = 74;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); int strengthLevel = 75;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(75); int defenceLevel = 72;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); int hitpointsLevel = 72;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(52); int magicLevel = 60;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); int rangeLevel = 44;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); int prayerLevel = 52;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72);
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 @Test
public void testOddPrayerLevelsNeededWhenNearNextCombatLevel() public void testOddPrayerLevelsNeededWhenNearNextCombatLevel()
{ {
when(player.getCombatLevel()).thenReturn(90); int attackLevel = 74;
when(client.getRealSkillLevel(Skill.ATTACK)).thenReturn(74); int strengthLevel = 75;
when(client.getRealSkillLevel(Skill.STRENGTH)).thenReturn(75); int defenceLevel = 72;
when(client.getRealSkillLevel(Skill.DEFENCE)).thenReturn(72); int hitpointsLevel = 72;
when(client.getRealSkillLevel(Skill.PRAYER)).thenReturn(53); int magicLevel = 60;
when(client.getRealSkillLevel(Skill.RANGED)).thenReturn(44); int rangeLevel = 44;
when(client.getRealSkillLevel(Skill.MAGIC)).thenReturn(60); int prayerLevel = 53;
when(client.getRealSkillLevel(Skill.HITPOINTS)).thenReturn(72);
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<String, Double> 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( int combatLevel = Experience.getCombatLevel(attackLevel, strengthLevel, defenceLevel, hitpointsLevel,
baseValues.get("base") + baseValues.get("max"), magicLevel, rangeLevel, prayerLevel);
player.getCombatLevel() + 1, int meleeNeed = Experience.getNextCombatLevelMelee(attackLevel, strengthLevel, defenceLevel, hitpointsLevel,
client.getRealSkillLevel(Skill.PRAYER) 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);
} }
} }