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 0c11d02621..088a88d544 100644 --- a/runelite-api/src/main/java/net/runelite/api/Experience.java +++ b/runelite-api/src/main/java/net/runelite/api/Experience.java @@ -47,6 +47,11 @@ public class Experience public static final int MAX_VIRT_LEVEL = 126; public static final int MAX_SKILL_XP = 200_000_000; + /** + * The maximum possible combat level. + */ + public static final int MAX_COMBAT_LEVEL = 126; + /** * The total experience required for each skill level. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java new file mode 100644 index 0000000000..cf910192f2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, Brett Middle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.combatlevel; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("combatlevel") +public interface CombatLevelConfig extends Config +{ + @ConfigItem( + keyName = "showLevelsUntil", + name = "Calculate next level", + description = "Mouse over the combat level to calculate what skill levels will increase combat." + ) + default boolean showLevelsUntil() + { + return true; + } +} 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 new file mode 100644 index 0000000000..7fda7c0f8a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018, Brett Middle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +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; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; +import net.runelite.client.util.ColorUtil; +import javax.inject.Inject; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; + +class CombatLevelOverlay extends Overlay +{ + private static final Color COMBAT_LEVEL_COLOUR = new Color(0xff981f); + + private final Client client; + private final CombatLevelConfig config; + private final TooltipManager tooltipManager; + + @Inject + private CombatLevelOverlay(Client client, CombatLevelConfig config, TooltipManager tooltipManager) + { + this.client = client; + this.config = config; + this.tooltipManager = tooltipManager; + } + + @Override + public Dimension render(Graphics2D graphics) + { + Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); + if (!config.showLevelsUntil() + || client.getLocalPlayer().getCombatLevel() == Experience.MAX_COMBAT_LEVEL + || combatLevelWidget == null || combatLevelWidget.isHidden()) + { + return null; + } + + Rectangle combatCanvas = combatLevelWidget.getBounds(); + + if (combatCanvas == null) + { + return null; + } + + if (combatCanvas.contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())) + { + tooltipManager.add(new Tooltip(getLevelsUntilTooltip())); + } + + return null; + } + + private String getLevelsUntilTooltip() + { + // grab combat skills from player + 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); + + // calculate initial required numbers + double base = 0.25 * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); + double melee = 0.325 * (attackLevel + strengthLevel); + double range = 0.325 * Math.floor(rangedLevel * 1.5); + double mage = 0.325 * Math.floor(magicLevel * 1.5); + 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, 0.325); + int hpdefNeed = calcLevels(base + max, next, 0.25); + int prayNeed = calcLevels(base + max, next, 0.125); + int rangeNeed = calcLevelsRM(rangedLevel, next, base); + int magicNeed = calcLevelsRM(magicLevel, next, base); + + // prayer is a special case, increasing combat every even level. need to correct its value + prayNeed = correctPrayer(prayerLevel, prayNeed); + + // create tooltip string + StringBuilder sb = new StringBuilder(); + sb.append(ColorUtil.wrapWithColorTag("Next combat level:
", COMBAT_LEVEL_COLOUR)); + + if ((attackLevel + strengthLevel + meleeNeed) <= 198) + { + sb.append(meleeNeed).append(" Attack/Strength
"); + } + if ((hitpointsLevel + defenceLevel + hpdefNeed) <= 198) + { + sb.append(hpdefNeed).append(" Defence/Hitpoints
"); + } + if ((rangedLevel + rangeNeed) <= 99) + { + sb.append(rangeNeed).append(" Ranged
"); + } + if ((magicLevel + magicNeed) <= 99) + { + sb.append(magicNeed).append(" Magic
"); + } + if ((prayerLevel + prayNeed) <= 99) + { + sb.append(prayNeed).append(" Prayer"); + } + return sb.toString(); + } + + /*** + * Calculate skill levels required for increasing combat level, meant + * for all combat skills besides 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((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 * 1.5) * 0.325; + return (int) Math.ceil((end - dhp - start) / 0.4875); + } + + /*** + * Corrects how many levels you need to level up combat through prayer. + * @param level current prayer level + * @param need needed prayer level calculated by calcLevels(...) + * @return a corrected number to increase combat through prayer only + */ + @VisibleForTesting + static int correctPrayer(int level, int need) + { + if ((level + need) % 2 == 1) + { + need++; + } + return need; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java index 73e33618bf..5facaecd93 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java @@ -25,6 +25,7 @@ package net.runelite.client.plugins.combatlevel; import com.google.common.eventbus.Subscribe; +import com.google.inject.Provides; import java.text.DecimalFormat; import javax.inject.Inject; import net.runelite.api.Client; @@ -34,8 +35,10 @@ import net.runelite.api.Skill; import net.runelite.api.events.GameTick; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( name = "Combat Level", @@ -43,14 +46,33 @@ import net.runelite.client.plugins.PluginDescriptor; ) public class CombatLevelPlugin extends Plugin { - private final DecimalFormat decimalFormat = new DecimalFormat("#.###"); + private final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); @Inject - Client client; + private Client client; + + @Inject + private CombatLevelOverlay overlay; + + @Inject + private OverlayManager overlayManager; + + @Provides + CombatLevelConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(CombatLevelConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } @Override protected void shutDown() throws Exception { + overlayManager.remove(overlay); Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); if (combatLevelWidget != null) @@ -88,6 +110,6 @@ public class CombatLevelPlugin extends Plugin client.getRealSkillLevel(Skill.PRAYER) ); - combatLevelWidget.setText("Combat Lvl: " + decimalFormat.format(combatLevelPrecise)); + combatLevelWidget.setText("Combat Lvl: " + DECIMAL_FORMAT.format(combatLevelPrecise)); } } 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 new file mode 100644 index 0000000000..b1c4604834 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/combatlevel/CombatLevelPluginTest.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2018, Brett Middle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +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.calcLevelsRM; +import static net.runelite.client.plugins.combatlevel.CombatLevelOverlay.correctPrayer; +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 +{ + private static final double ATT_STR_MULT = 0.325; + private static final double DEF_HP_MULT = 0.25; + private static final double PRAY_MULT = 0.125; + + @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 = 0.25 * (defenceLevel + hitpointsLevel + Math.floor(prayerLevel / 2)); + double melee = 0.325 * (attackLevel + strengthLevel); + double range = 0.325 * Math.floor(rangedLevel * 1.5); + double mage = 0.325 * Math.floor(magicLevel * 1.5); + 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); + + HashMap baseValues = getBaseValues(); + + // test attack/strength + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), + player.getCombatLevel() + 1, ATT_STR_MULT)); + + // test defence/hitpoints + assertEquals(3, calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, DEF_HP_MULT)); + + // test prayer + int prayNeed = calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, PRAY_MULT); + assertEquals(5, correctPrayer(client.getRealSkillLevel(Skill.PRAYER), prayNeed)); + + // test ranged + assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), + player.getCombatLevel() + 1, baseValues.get("base"))); + + // test magic + assertEquals(2, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), + player.getCombatLevel() + 1, baseValues.get("base"))); + } + + @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); + + HashMap baseValues = getBaseValues(); + + // test attack/strength + assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("melee"), + player.getCombatLevel() + 1, ATT_STR_MULT)); + + // test defence/hitpoints + assertEquals(1, calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, DEF_HP_MULT)); + + // test prayer + int prayNeed = calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, PRAY_MULT); + assertEquals(2, correctPrayer(client.getRealSkillLevel(Skill.PRAYER), prayNeed)); + + // test ranged + assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), + player.getCombatLevel() + 1, baseValues.get("base"))); + + // test magic + assertEquals(4, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), + player.getCombatLevel() + 1, baseValues.get("base"))); + } + + @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); + + HashMap baseValues = getBaseValues(); + + // test attack/strength + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), + player.getCombatLevel() + 1, ATT_STR_MULT)); + + // test defence/hitpoints + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, DEF_HP_MULT)); + + // test prayer + int prayNeed = calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, PRAY_MULT); + assertEquals(4, correctPrayer(client.getRealSkillLevel(Skill.PRAYER), prayNeed)); + + // test ranged + assertEquals(17, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), + player.getCombatLevel() + 1, baseValues.get("base"))); + + // test magic + assertEquals(19, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), + player.getCombatLevel() + 1, baseValues.get("base"))); + } + + @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); + + HashMap baseValues = getBaseValues(); + + // test attack/strength + assertEquals(18, calcLevels(baseValues.get("base") + baseValues.get("melee"), + player.getCombatLevel() + 1, ATT_STR_MULT)); + + // test defence/hitpoints + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, DEF_HP_MULT)); + + // test prayer + int prayNeed = calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, PRAY_MULT); + assertEquals(3, correctPrayer(client.getRealSkillLevel(Skill.PRAYER), prayNeed)); + + // test ranged + assertEquals(14, calcLevelsRM(client.getRealSkillLevel(Skill.RANGED), + player.getCombatLevel() + 1, baseValues.get("base"))); + + // test magic + assertEquals(1, calcLevelsRM(client.getRealSkillLevel(Skill.MAGIC), + player.getCombatLevel() + 1, baseValues.get("base"))); + } + + @Test + public void testPlayerZezima() + { + // 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); + + HashMap baseValues = getBaseValues(); + + // test attack/strength + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("melee"), + player.getCombatLevel() + 1, ATT_STR_MULT)); + + // test defence/hitpoints + assertEquals(2, calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, DEF_HP_MULT)); + + // test prayer + int prayNeed = calcLevels(baseValues.get("base") + baseValues.get("max"), + player.getCombatLevel() + 1, PRAY_MULT); + assertEquals(4, correctPrayer(client.getRealSkillLevel(Skill.PRAYER), prayNeed)); + } +}