Merge pull request #14129 from TalSk/imbued-heart-timer

This commit is contained in:
Jordan
2021-11-04 19:18:29 +00:00
committed by GitHub
3 changed files with 55 additions and 169 deletions

View File

@@ -529,6 +529,13 @@ public enum Varbits
VENGEANCE_COOLDOWN(2451), VENGEANCE_COOLDOWN(2451),
CORRUPTION_COOLDOWN(12288), CORRUPTION_COOLDOWN(12288),
/**
* Imbued Heart cooldown
* Number of game tick remaining on cooldown in intervals of 10; for a value X there are 10 * X game ticks remaining.
* The heart regains its power once this reaches 0.
*/
IMBUED_HEART_COOLDOWN(5361),
/** /**
* Amount of items in each bank tab * Amount of items in each bank tab
*/ */

View File

@@ -39,7 +39,6 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Constants; import net.runelite.api.Constants;
import net.runelite.api.EquipmentInventorySlot; import net.runelite.api.EquipmentInventorySlot;
import net.runelite.api.GameState;
import net.runelite.api.InventoryID; import net.runelite.api.InventoryID;
import net.runelite.api.Item; import net.runelite.api.Item;
import net.runelite.api.ItemContainer; import net.runelite.api.ItemContainer;
@@ -62,7 +61,6 @@ import net.runelite.api.events.GraphicChanged;
import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.VarbitChanged; import net.runelite.api.events.VarbitChanged;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE; import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE;
@@ -105,7 +103,6 @@ public class TimersPlugin extends Plugin
private static final String FROZEN_MESSAGE = "<col=ef1020>You have been frozen!</col>"; private static final String FROZEN_MESSAGE = "<col=ef1020>You have been frozen!</col>";
private static final String GAUNTLET_ENTER_MESSAGE = "You enter the Gauntlet."; private static final String GAUNTLET_ENTER_MESSAGE = "You enter the Gauntlet.";
private static final String GOD_WARS_ALTAR_MESSAGE = "you recharge your prayer."; private static final String GOD_WARS_ALTAR_MESSAGE = "you recharge your prayer.";
private static final String IMBUED_HEART_READY_MESSAGE = "<col=ef1020>Your imbued heart has regained its magical power.</col>";
private static final String MAGIC_IMBUE_EXPIRED_MESSAGE = "Your Magic Imbue charge has ended."; private static final String MAGIC_IMBUE_EXPIRED_MESSAGE = "Your Magic Imbue charge has ended.";
private static final String MAGIC_IMBUE_MESSAGE = "You are charged to combine runes!"; private static final String MAGIC_IMBUE_MESSAGE = "You are charged to combine runes!";
private static final String STAFF_OF_THE_DEAD_SPEC_EXPIRED_MESSAGE = "Your protection fades away"; private static final String STAFF_OF_THE_DEAD_SPEC_EXPIRED_MESSAGE = "Your protection fades away";
@@ -153,14 +150,14 @@ public class TimersPlugin extends Plugin
private int lastPoisonVarp; private int lastPoisonVarp;
private int lastPvpVarb; private int lastPvpVarb;
private int lastCorruptionVarb; private int lastCorruptionVarb;
private int lastImbuedHeartVarb;
private boolean imbuedHeartTimerActive;
private int nextPoisonTick; private int nextPoisonTick;
private WorldPoint lastPoint; private WorldPoint lastPoint;
private TeleportWidget lastTeleportClicked; private TeleportWidget lastTeleportClicked;
private int lastAnimation; private int lastAnimation;
private boolean widgetHiddenChangedOnPvpWorld; private boolean widgetHiddenChangedOnPvpWorld;
private ElapsedTimer tzhaarTimer; private ElapsedTimer tzhaarTimer;
private int imbuedHeartClickTick = -1;
private int lastBoostedMagicLevel = -1;
@Inject @Inject
private ItemManager itemManager; private ItemManager itemManager;
@@ -186,10 +183,6 @@ public class TimersPlugin extends Plugin
@Override @Override
public void startUp() public void startUp()
{ {
if (client.getGameState() == GameState.LOGGED_IN)
{
lastBoostedMagicLevel = client.getBoostedSkillLevel(Skill.MAGIC);
}
} }
@Override @Override
@@ -205,8 +198,8 @@ public class TimersPlugin extends Plugin
nextPoisonTick = 0; nextPoisonTick = 0;
removeTzhaarTimer(); removeTzhaarTimer();
staminaTimer = null; staminaTimer = null;
imbuedHeartClickTick = -1; imbuedHeartTimerActive = false;
lastBoostedMagicLevel = -1; lastImbuedHeartVarb = 0;
} }
@Subscribe @Subscribe
@@ -218,6 +211,7 @@ public class TimersPlugin extends Plugin
int poisonVarp = client.getVar(VarPlayer.POISON); int poisonVarp = client.getVar(VarPlayer.POISON);
int pvpVarb = client.getVar(Varbits.PVP_SPEC_ORB); int pvpVarb = client.getVar(Varbits.PVP_SPEC_ORB);
int corruptionCooldownVarb = client.getVar(Varbits.CORRUPTION_COOLDOWN); int corruptionCooldownVarb = client.getVar(Varbits.CORRUPTION_COOLDOWN);
int imbuedHeartCooldownVarb = client.getVar(Varbits.IMBUED_HEART_COOLDOWN);
if (lastRaidVarb != raidVarb) if (lastRaidVarb != raidVarb)
{ {
@@ -308,6 +302,22 @@ public class TimersPlugin extends Plugin
lastPvpVarb = pvpVarb; lastPvpVarb = pvpVarb;
} }
if (lastImbuedHeartVarb != imbuedHeartCooldownVarb && config.showImbuedHeart())
{
if (imbuedHeartCooldownVarb == 0)
{
removeGameTimer(IMBUEDHEART);
imbuedHeartTimerActive = false;
}
else if (!imbuedHeartTimerActive)
{
createGameTimer(IMBUEDHEART, Duration.of(10L * imbuedHeartCooldownVarb, RSTimeUnit.GAME_TICKS));
imbuedHeartTimerActive = true;
}
lastImbuedHeartVarb = imbuedHeartCooldownVarb;
}
} }
@Subscribe @Subscribe
@@ -375,6 +385,7 @@ public class TimersPlugin extends Plugin
if (!config.showImbuedHeart()) if (!config.showImbuedHeart())
{ {
removeGameTimer(IMBUEDHEART); removeGameTimer(IMBUEDHEART);
imbuedHeartTimerActive = false;
} }
if (!config.showStaffOfTheDead()) if (!config.showStaffOfTheDead())
@@ -481,12 +492,6 @@ public class TimersPlugin extends Plugin
return; return;
} }
if (event.getMenuOption().contains("Invigorate")
&& event.getId() == ItemID.IMBUED_HEART)
{
imbuedHeartClickTick = client.getTickCount();
}
TeleportWidget teleportWidget = TeleportWidget.of(event.getParam1()); TeleportWidget teleportWidget = TeleportWidget.of(event.getParam1());
if (teleportWidget != null) if (teleportWidget != null)
{ {
@@ -636,11 +641,6 @@ public class TimersPlugin extends Plugin
removeGameTimer(SUPERANTIFIRE); removeGameTimer(SUPERANTIFIRE);
} }
if (config.showImbuedHeart() && message.equals(IMBUED_HEART_READY_MESSAGE))
{
removeGameTimer(IMBUEDHEART);
}
if (config.showPrayerEnhance() && message.startsWith("You drink some of your") && message.contains("prayer enhance")) if (config.showPrayerEnhance() && message.startsWith("You drink some of your") && message.contains("prayer enhance"))
{ {
createGameTimer(PRAYER_ENHANCE); createGameTimer(PRAYER_ENHANCE);
@@ -922,7 +922,6 @@ public class TimersPlugin extends Plugin
} }
break; break;
case LOGIN_SCREEN: case LOGIN_SCREEN:
lastBoostedMagicLevel = -1;
// fall through // fall through
case HOPPING: case HOPPING:
// pause tzhaar timer if logged out without pausing // pause tzhaar timer if logged out without pausing
@@ -1100,37 +1099,6 @@ public class TimersPlugin extends Plugin
} }
} }
@Subscribe
public void onStatChanged(StatChanged statChanged)
{
if (statChanged.getSkill() != Skill.MAGIC)
{
return;
}
final int boostedMagicLevel = statChanged.getBoostedLevel();
if (imbuedHeartClickTick < 0
|| client.getTickCount() > imbuedHeartClickTick + 3 // allow for 2 ticks of lag
|| !config.showImbuedHeart())
{
lastBoostedMagicLevel = boostedMagicLevel;
return;
}
final int boostAmount = boostedMagicLevel - statChanged.getLevel();
final int boostChange = boostedMagicLevel - lastBoostedMagicLevel;
final int heartBoost = 1 + (statChanged.getLevel() / 10);
if ((boostAmount == heartBoost || (lastBoostedMagicLevel != -1 && boostChange == heartBoost))
&& boostChange > 0)
{
createGameTimer(IMBUEDHEART);
}
lastBoostedMagicLevel = boostedMagicLevel;
}
private void createStaminaTimer() private void createStaminaTimer()
{ {
Duration duration = Duration.ofMinutes(wasWearingEndurance ? 4 : 2); Duration duration = Duration.ofMinutes(wasWearingEndurance ? 4 : 2);

View File

@@ -33,16 +33,12 @@ import java.time.Instant;
import java.util.function.Predicate; import java.util.function.Predicate;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Experience;
import net.runelite.api.InventoryID; import net.runelite.api.InventoryID;
import net.runelite.api.ItemContainer; import net.runelite.api.ItemContainer;
import net.runelite.api.ItemID;
import net.runelite.api.Skill; import net.runelite.api.Skill;
import net.runelite.api.Varbits; import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.VarbitChanged; import net.runelite.api.events.VarbitChanged;
import net.runelite.client.game.ItemManager; import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager; import net.runelite.client.game.SpriteManager;
@@ -63,11 +59,9 @@ import static org.mockito.ArgumentMatchers.nullable;
import org.mockito.Mock; import org.mockito.Mock;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@@ -327,7 +321,7 @@ public class TimersPluginTest
assertTrue(captor.getValue() instanceof ElapsedTimer); assertTrue(captor.getValue() instanceof ElapsedTimer);
// test timer pause: verify the added ElapsedTimer has a non-null lastTime // test timer pause: verify the added ElapsedTimer has a non-null lastTime
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>The Inferno has been paused. You may now log out.", "", 0); chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>The Inferno has been paused. You may now log out.", "", 0);
timersPlugin.onChatMessage(chatMessage); timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(1)).removeInfoBox(captor.capture()); verify(infoBoxManager, times(1)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(2)).addInfoBox(captor.capture()); verify(infoBoxManager, times(2)).addInfoBox(captor.capture());
@@ -337,7 +331,7 @@ public class TimersPluginTest
Instant oldTime = ((ElapsedTimer) captor.getValue()).getStartTime(); Instant oldTime = ((ElapsedTimer) captor.getValue()).getStartTime();
// test timer unpause: verify the last time is null after being unpaused // test timer unpause: verify the last time is null after being unpaused
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>Wave: 2</col>", "", 0); chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "<col=ef1020>Wave: 2</col>", "", 0);
timersPlugin.onChatMessage(chatMessage); timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(2)).removeInfoBox(captor.capture()); verify(infoBoxManager, times(2)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(3)).addInfoBox(captor.capture()); verify(infoBoxManager, times(3)).addInfoBox(captor.capture());
@@ -346,7 +340,7 @@ public class TimersPluginTest
assertNull(timer.getLastTime()); assertNull(timer.getLastTime());
// test timer remove: verify the infobox was removed (and no more were added) // test timer remove: verify the infobox was removed (and no more were added)
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have been defeated!", "", 0); chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have been defeated!", "", 0);
timersPlugin.onChatMessage(chatMessage); timersPlugin.onChatMessage(chatMessage);
verify(infoBoxManager, times(3)).removeInfoBox(captor.capture()); verify(infoBoxManager, times(3)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(3)).addInfoBox(captor.capture()); verify(infoBoxManager, times(3)).addInfoBox(captor.capture());
@@ -543,123 +537,40 @@ public class TimersPluginTest
// endregion // endregion
@Test @Test
public void testImbuedHeartBoost() public void testImbuedHeartStart()
{ {
when(timersConfig.showImbuedHeart()).thenReturn(true); when(timersConfig.showImbuedHeart()).thenReturn(true);
when(client.getTickCount()).thenReturn(100); when(client.getVar(Varbits.IMBUED_HEART_COOLDOWN)).thenReturn(70);
StatChanged event; timersPlugin.onVarbitChanged(new VarbitChanged());
final MenuOptionClicked imbuedHeartClick = new MenuOptionClicked(); ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
imbuedHeartClick.setMenuOption("Invigorate"); verify(infoBoxManager).addInfoBox(captor.capture());
imbuedHeartClick.setId(ItemID.IMBUED_HEART); TimerTimer infoBox = (TimerTimer) captor.getValue();
timersPlugin.onMenuOptionClicked(imbuedHeartClick); assertEquals(GameTimer.IMBUEDHEART, infoBox.getTimer());
assertEquals(GameTimer.IMBUEDHEART.getDuration(), infoBox.getDuration());
when(client.getTickCount()).thenReturn(101);
for (int level = 1, i = 0; level <= Experience.MAX_REAL_LEVEL; level++, i++)
{
event = new StatChanged(Skill.MAGIC, 0, level, heartBoostedLevel(level));
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());
}
} }
@Test @Test
public void testImbuedHeartBoostFromDrained() public void testImbuedHeartEnd()
{ {
when(timersConfig.showImbuedHeart()).thenReturn(true); when(timersConfig.showImbuedHeart()).thenReturn(true);
when(client.getTickCount()).thenReturn(100);
final MenuOptionClicked imbuedHeartClick = new MenuOptionClicked(); when(client.getVar(Varbits.IMBUED_HEART_COOLDOWN)).thenReturn(70);
imbuedHeartClick.setMenuOption("Invigorate"); timersPlugin.onVarbitChanged(new VarbitChanged()); // Calls removeIf once (on createGameTimer)
imbuedHeartClick.setId(ItemID.IMBUED_HEART);
timersPlugin.onMenuOptionClicked(imbuedHeartClick);
when(client.getTickCount()).thenReturn(101); ArgumentCaptor<Predicate<InfoBox>> prcaptor = ArgumentCaptor.forClass(Predicate.class);
TimerTimer imbuedHeartInfoBox = new TimerTimer(GameTimer.IMBUEDHEART, Duration.ofSeconds(420), timersPlugin);
verify(infoBoxManager, times (1)).addInfoBox(any());
verify(infoBoxManager, times(1)).removeIf(prcaptor.capture());
Predicate<InfoBox> pred = prcaptor.getValue();
assertTrue(pred.test(imbuedHeartInfoBox));
for (int level = 1, i = 0; level <= Experience.MAX_REAL_LEVEL; level++, i++) when(client.getVar(Varbits.IMBUED_HEART_COOLDOWN)).thenReturn(0);
{ timersPlugin.onVarbitChanged(new VarbitChanged()); // Calls removeIf once
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, level - 1));
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, heartBoostedLevel(level) - 1));
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class); verify(infoBoxManager, times(1)).addInfoBox(any());
verify(infoBoxManager, times(i + 1)).addInfoBox(captor.capture()); verify(infoBoxManager, times(2)).removeIf(prcaptor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue(); pred = prcaptor.getValue();
assertEquals(GameTimer.IMBUEDHEART, infoBox.getTimer()); assertTrue(pred.test(imbuedHeartInfoBox));
}
}
@Test
public void testImbuedHeartBoostFromPartialBoost()
{
when(timersConfig.showImbuedHeart()).thenReturn(true);
when(client.getTickCount()).thenReturn(100);
final MenuOptionClicked imbuedHeartClick = new MenuOptionClicked();
imbuedHeartClick.setMenuOption("Invigorate");
imbuedHeartClick.setId(ItemID.IMBUED_HEART);
timersPlugin.onMenuOptionClicked(imbuedHeartClick);
when(client.getTickCount()).thenReturn(101);
for (int level = 10, i = 0; level <= Experience.MAX_REAL_LEVEL; level++, i++)
{
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, level + 1));
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, heartBoostedLevel(level)));
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());
}
}
@Test
public void testNonImbuedHeartBoost()
{
lenient().when(timersConfig.showImbuedHeart()).thenReturn(true);
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 1, 1));
// Simulate stat changes of imbued heart boost amount without having clicked the imbued heart
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 29, 34)); // equal to magic essence
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 39, 43)); // equal to magic potion
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 49, 54)); // equal to spicy stew
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 99, 109));
verifyNoInteractions(infoBoxManager);
}
@Test
public void testMagicLevelDrain()
{
lenient().when(timersConfig.showImbuedHeart()).thenReturn(true);
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, 1, 1));
when(client.getTickCount()).thenReturn(100);
final MenuOptionClicked imbuedHeartClick = new MenuOptionClicked();
imbuedHeartClick.setMenuOption("Invigorate");
imbuedHeartClick.setId(ItemID.IMBUED_HEART);
timersPlugin.onMenuOptionClicked(imbuedHeartClick);
when(client.getTickCount()).thenReturn(101);
// Simulate stat changes draining to the imbued heart boost amount
for (int level = 1; level <= Experience.MAX_REAL_LEVEL; level++)
{
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, level));
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, heartBoostedLevel(level) + 1));
timersPlugin.onStatChanged(new StatChanged(Skill.MAGIC, 0, level, heartBoostedLevel(level)));
}
verifyNoInteractions(infoBoxManager);
}
private static int heartBoostedLevel(final int level)
{
return level + 1 + (level / 10);
} }
} }