timers plugin: add support for ring of endurance to stam timer

This commit is contained in:
Adam
2020-06-11 23:02:03 -04:00
parent 9535f066b9
commit 51f0b7752d
4 changed files with 114 additions and 31 deletions

View File

@@ -40,7 +40,7 @@ import static net.runelite.client.util.RSTimeUnit.GAME_TICKS;
@Getter(AccessLevel.PACKAGE)
enum GameTimer
{
STAMINA(ItemID.STAMINA_POTION4, GameTimerImageType.ITEM, "Stamina", 2, ChronoUnit.MINUTES, true),
STAMINA(ItemID.STAMINA_POTION4, GameTimerImageType.ITEM, "Stamina", true),
ANTIFIRE(ItemID.ANTIFIRE_POTION4, GameTimerImageType.ITEM, "Antifire", 6, ChronoUnit.MINUTES),
EXANTIFIRE(ItemID.EXTENDED_ANTIFIRE4, GameTimerImageType.ITEM, "Extended antifire", 12, ChronoUnit.MINUTES),
OVERLOAD(ItemID.OVERLOAD_4, GameTimerImageType.ITEM, "Overload", 5, ChronoUnit.MINUTES, true),
@@ -78,8 +78,8 @@ enum GameTimer
DIVINE_MAGIC(ItemID.DIVINE_MAGIC_POTION4, GameTimerImageType.ITEM, "Divine Magic", 5, ChronoUnit.MINUTES),
DIVINE_BASTION(ItemID.DIVINE_BASTION_POTION4, GameTimerImageType.ITEM, "Divine Bastion", 5, ChronoUnit.MINUTES),
DIVINE_BATTLEMAGE(ItemID.DIVINE_BATTLEMAGE_POTION4, GameTimerImageType.ITEM, "Divine Battlemage", 5, ChronoUnit.MINUTES),
ANTIPOISON(ItemID.ANTIPOISON4, GameTimerImageType.ITEM, "Antipoison"),
ANTIVENOM(ItemID.ANTIVENOM4, GameTimerImageType.ITEM, "Anti-venom");
ANTIPOISON(ItemID.ANTIPOISON4, GameTimerImageType.ITEM, "Antipoison", false),
ANTIVENOM(ItemID.ANTIVENOM4, GameTimerImageType.ITEM, "Anti-venom", false);
@Nullable
private final Duration duration;
@@ -110,12 +110,12 @@ enum GameTimer
this(imageId, idType, description, null, time, unit, false);
}
GameTimer(int imageId, GameTimerImageType idType, String description)
GameTimer(int imageId, GameTimerImageType idType, String description, boolean removedOnDeath)
{
this.duration = null;
this.graphicId = null;
this.description = description;
this.removedOnDeath = false;
this.removedOnDeath = removedOnDeath;
this.imageId = imageId;
this.imageType = idType;
}

View File

@@ -27,6 +27,7 @@ package net.runelite.client.plugins.timers;
import com.google.inject.Provides;
import java.time.Duration;
import java.time.Instant;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
@@ -107,6 +108,7 @@ public class TimersPlugin extends Plugin
private static final String SUPER_ANTIFIRE_EXPIRED_MESSAGE = "<col=7f007f>Your super antifire potion has expired.</col>";
private static final String KILLED_TELEBLOCK_OPPONENT_TEXT = "Your Tele Block has been removed because you killed ";
private static final String PRAYER_ENHANCE_EXPIRED = "<col=ff0000>Your prayer enhance effect has worn off.</col>";
private static final String ENDURANCE_EFFECT_MESSAGE = "Your Ring of endurance doubles the duration of your stamina potion's effect.";
private static final Pattern DEADMAN_HALF_TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you by (.+)\\. It will expire in 1 minute, 15 seconds\\.</col>");
private static final Pattern FULL_TELEBLOCK_PATTERN = Pattern.compile("A Tele Block spell has been cast on you by (.+)\\. It will expire in 5 minutes\\.</col>");
@@ -118,6 +120,9 @@ public class TimersPlugin extends Plugin
private TimerTimer freezeTimer;
private int freezeTime = -1; // time frozen, in game ticks
private TimerTimer staminaTimer;
private boolean wasWearingEndurance;
private int lastRaidVarb;
private int lastWildernessVarb;
private int lastVengCooldownVarb;
@@ -163,6 +168,7 @@ public class TimersPlugin extends Plugin
widgetHiddenChangedOnPvpWorld = false;
lastPoisonVarp = 0;
nextPoisonTick = 0;
staminaTimer = null;
}
@Subscribe
@@ -379,7 +385,7 @@ public class TimersPlugin extends Plugin
|| event.getId() == ItemID.EGNIOL_POTION_4))
{
// Needs menu option hook because mixes use a common drink message, distinct from their standard potion messages
createGameTimer(STAMINA);
createStaminaTimer();
return;
}
@@ -438,14 +444,20 @@ public class TimersPlugin extends Plugin
return;
}
if (config.showStamina() && (event.getMessage().equals(STAMINA_DRINK_MESSAGE) || event.getMessage().equals(STAMINA_SHARED_DRINK_MESSAGE)))
if (event.getMessage().equals(ENDURANCE_EFFECT_MESSAGE))
{
createGameTimer(STAMINA);
wasWearingEndurance = true;
}
if (config.showStamina() && (event.getMessage().equals(STAMINA_EXPIRED_MESSAGE) || event.getMessage().equals(GAUNTLET_ENTER_MESSAGE)))
if (config.showStamina() && (event.getMessage().equals(STAMINA_DRINK_MESSAGE) || event.getMessage().equals(STAMINA_SHARED_DRINK_MESSAGE)))
{
createStaminaTimer();
}
if (event.getMessage().equals(STAMINA_EXPIRED_MESSAGE) || event.getMessage().equals(GAUNTLET_ENTER_MESSAGE))
{
removeGameTimer(STAMINA);
staminaTimer = null;
}
if (config.showAntiFire() && event.getMessage().equals(ANTIFIRE_DRINK_MESSAGE))
@@ -797,34 +809,50 @@ public class TimersPlugin extends Plugin
}
/**
* remove SOTD timer when weapon is changed
*
* @param itemContainerChanged
* Remove SOTD timer and update stamina timer when equipment is changed.
*/
@Subscribe
public void onItemContainerChanged(ItemContainerChanged itemContainerChanged)
{
ItemContainer container = itemContainerChanged.getItemContainer();
if (container == client.getItemContainer(InventoryID.EQUIPMENT))
if (itemContainerChanged.getContainerId() != InventoryID.EQUIPMENT.getId())
{
Item weapon = container.getItem(EquipmentInventorySlot.WEAPON.getSlotIdx());
return;
}
if (weapon == null)
{
removeGameTimer(STAFF_OF_THE_DEAD);
return;
}
ItemContainer container = itemContainerChanged.getItemContainer();
switch (weapon.getId())
Item weapon = container.getItem(EquipmentInventorySlot.WEAPON.getSlotIdx());
if (weapon == null ||
(weapon.getId() != ItemID.STAFF_OF_THE_DEAD &&
weapon.getId() != ItemID.TOXIC_STAFF_OF_THE_DEAD &&
weapon.getId() != ItemID.STAFF_OF_LIGHT &&
weapon.getId() != ItemID.TOXIC_STAFF_UNCHARGED))
{
// remove sotd timer if the staff has been unwielded
removeGameTimer(STAFF_OF_THE_DEAD);
}
if (wasWearingEndurance)
{
Item ring = container.getItem(EquipmentInventorySlot.RING.getSlotIdx());
// when using the last ring charge the ring changes to the uncharged version, ignore that and don't
// halve the timer
if (ring == null || (ring.getId() != ItemID.RING_OF_ENDURANCE && ring.getId() != ItemID.RING_OF_ENDURANCE_UNCHARGED_24844))
{
case ItemID.STAFF_OF_THE_DEAD:
case ItemID.TOXIC_STAFF_OF_THE_DEAD:
case ItemID.STAFF_OF_LIGHT:
case ItemID.TOXIC_STAFF_UNCHARGED:
// don't reset timer if still wielding staff
return;
default:
removeGameTimer(STAFF_OF_THE_DEAD);
wasWearingEndurance = false;
if (staminaTimer != null)
{
// Remaining duration gets divided by 2
Duration remainingDuration = Duration.between(Instant.now(), staminaTimer.getEndTime()).dividedBy(2);
// This relies on the chat message to be removed, which could be after the timer has been culled;
// so check there is still remaining time
if (!remainingDuration.isNegative() && !remainingDuration.isZero())
{
log.debug("Halving stamina timer");
staminaTimer.setDuration(remainingDuration);
}
}
}
}
}
@@ -856,6 +884,12 @@ public class TimersPlugin extends Plugin
}
}
private void createStaminaTimer()
{
Duration duration = Duration.ofMinutes(wasWearingEndurance ? 4 : 2);
staminaTimer = createGameTimer(STAMINA, duration);
}
private TimerTimer createGameTimer(final GameTimer timer)
{
if (timer.getDuration() == null)

View File

@@ -39,8 +39,8 @@ import net.runelite.client.plugins.Plugin;
public class Timer extends InfoBox
{
private final Instant startTime;
private final Instant endTime;
private final Duration duration;
private Instant endTime;
private Duration duration;
public Timer(long period, ChronoUnit unit, BufferedImage image, Plugin plugin)
{
@@ -94,4 +94,9 @@ public class Timer extends InfoBox
return timeLeft.isZero() || timeLeft.isNegative();
}
public void setDuration(Duration duration)
{
this.duration = duration;
endTime = startTime.plus(duration);
}
}

View File

@@ -28,16 +28,21 @@ import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import java.time.Duration;
import java.util.EnumSet;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.ItemContainer;
import net.runelite.api.WorldType;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.SpriteManager;
import net.runelite.client.ui.overlay.infobox.InfoBox;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,6 +50,7 @@ import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.any;
import org.mockito.Mock;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@@ -189,4 +195,42 @@ public class TimersPluginTest
verify(infoBoxManager, atLeastOnce()).removeIf(any());
}
@Test
public void testStamina()
{
when(timersConfig.showStamina()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your stamina potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.STAMINA, infoBox.getTimer());
assertEquals(Duration.ofMinutes(2), infoBox.getDuration());
}
@Test
public void testEndurance()
{
when(timersConfig.showStamina()).thenReturn(true);
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "Your Ring of endurance doubles the duration of your stamina potion's effect.", "", 0);
timersPlugin.onChatMessage(chatMessage);
chatMessage = new ChatMessage(null, ChatMessageType.SPAM, "", "You drink some of your stamina potion.", "", 0);
timersPlugin.onChatMessage(chatMessage);
ArgumentCaptor<InfoBox> captor = ArgumentCaptor.forClass(InfoBox.class);
verify(infoBoxManager).addInfoBox(captor.capture());
TimerTimer infoBox = (TimerTimer) captor.getValue();
assertEquals(GameTimer.STAMINA, infoBox.getTimer());
assertEquals(Duration.ofMinutes(4), infoBox.getDuration());
// unwield ring
timersPlugin.onItemContainerChanged(new ItemContainerChanged(InventoryID.EQUIPMENT.getId(), mock(ItemContainer.class)));
// some time has elapsed in the test; this should be just under 2 mins
int mins = (int) infoBox.getDuration().toMinutes();
assertTrue(mins == 1 || mins == 2);
}
}