Skip to content

Commit

Permalink
timers plugin: Improve imbued heart detection
Browse files Browse the repository at this point in the history
As is the case with other graphics-based timers, the imbued heart timer
will not fire if enough other graphics animations are triggered (such as
those created when fighting the Dagannoth Kings). To add this timer more
reliably, this commit will add the timer when a Magic stat boost occurs
which is large enough that it can only be triggered by the heart.

Because the heart's boost scales with the player's level, it gives an
equal boost to the Magic essence and Magic potion boosts, depending on
the base magic level. To account for this, it will only be applied if
the user's base magic level is high enough to assuredly identify that a
potion was not used to trigger the boost.

Fixes runelite/runelite#3516

Co-authored-by: Lucas <[email protected]>
  • Loading branch information
2 people authored and Adam- committed Feb 8, 2020
1 parent 1a9efe8 commit 45c5df3
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
package net.runelite.client.plugins.timers;

import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Provides;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand All @@ -43,10 +44,12 @@
import net.runelite.api.NPC;
import net.runelite.api.NpcID;
import net.runelite.api.Player;
import net.runelite.api.Skill;
import net.runelite.api.Varbits;
import net.runelite.api.WorldType;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.ChatMessage;
import net.runelite.client.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
Expand Down Expand Up @@ -112,6 +115,9 @@ public class TimersPlugin extends Plugin
private static final Pattern HALF_TELEBLOCK_PATTERN = Pattern.compile("<col=4f006f>A Tele Block spell has been cast on you by (.+)\\. It will expire in 2 minutes, 30 seconds\\.</col>");
private static final Pattern DIVINE_POTION_PATTERN = Pattern.compile("You drink some of your divine (.+) potion\\.");

@VisibleForTesting
static final int IMBUED_HEART_MIN_CERTAIN_BOOST_LEVEL = 40; // Before this level, other effects can grant boosts of equal amounts

private TimerTimer freezeTimer;
private int freezeTime = -1; // time frozen, in game ticks

Expand Down Expand Up @@ -892,6 +898,24 @@ public void onPlayerDeath(PlayerDeath playerDeath)
}
}

@Subscribe
public void onStatChanged(StatChanged statChanged)
{
if (statChanged.getSkill() != Skill.MAGIC || !config.showImbuedHeart())
{
return;
}

final int magicLevel = statChanged.getLevel();
final int boostAmount = statChanged.getBoostedLevel() - magicLevel;
final int heartBoost = 1 + (magicLevel / 10);

if (magicLevel >= IMBUED_HEART_MIN_CERTAIN_BOOST_LEVEL && boostAmount == heartBoost)
{
createGameTimer(IMBUEDHEART);
}
}

private TimerTimer createGameTimer(final GameTimer timer)
{
removeGameTimer(timer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@
import java.util.EnumSet;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.api.WorldType;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.StatChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.ui.overlay.infobox.InfoBox;
Expand All @@ -42,7 +45,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
Expand Down Expand Up @@ -136,4 +142,44 @@ public void testDmmFullTb()
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.DMM_FULLTB, infoBox.getTimer());
}
}

@Test
public void testImbuedHeartBoost()
{
when(timersConfig.showImbuedHeart()).thenReturn(true);
StatChanged event;

// The following simulates imbued heart boosts at low magic levels, but should not create an imbued heart timer
// because it is ambiguous what caused the boost. (Magic essences and potions can create similar boost amounts)
for (int level = 1; level < TimersPlugin.IMBUED_HEART_MIN_CERTAIN_BOOST_LEVEL; level++)
{
event = new StatChanged(Skill.MAGIC, 0, level, level + 1 + (level / 10));
timersPlugin.onStatChanged(event);
verify(infoBoxManager, never()).addInfoBox(any());
}

// The following simulates magic essence and magic potion boosts and should not create an imbued heart timer
for (int level = TimersPlugin.IMBUED_HEART_MIN_CERTAIN_BOOST_LEVEL; level <= Experience.MAX_REAL_LEVEL; level++)
{
event = new StatChanged(Skill.MAGIC, 0, level, level + 3); // Magic essence
timersPlugin.onStatChanged(event);
verify(infoBoxManager, never()).addInfoBox(any());

event = new StatChanged(Skill.MAGIC, 0, level, level + 4);
timersPlugin.onStatChanged(event);
verify(infoBoxManager, never()).addInfoBox(any());
}

// The following simulates a real imbued heart magic boost and should create imbued heart timers
for (int level = TimersPlugin.IMBUED_HEART_MIN_CERTAIN_BOOST_LEVEL, i = 0; level <= Experience.MAX_REAL_LEVEL; level++, i++)
{
event = new StatChanged(Skill.MAGIC, 0, level, level + 1 + (level / 10));
timersPlugin.onStatChanged(event);

ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager, times(i + 1)).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.IMBUEDHEART, infoBox.getTimer());
}
}
}

0 comments on commit 45c5df3

Please sign in to comment.