diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index b55956dd20..ee72d85f2b 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -496,7 +496,9 @@ public enum Varbits EXPLORER_RING_ALCHTYPE(5398), EXPLORER_RING_TELEPORTS(4552), EXPLORER_RING_ALCHS(4554), - EXPLORER_RING_RUNENERGY(4553); + EXPLORER_RING_RUNENERGY(4553), + + WINTERTODT_TIMER(7980); /** * The raw varbit ID. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java index 8fd6e6e446..6b1adb7e9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtConfig.java @@ -29,6 +29,7 @@ import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; import net.runelite.client.plugins.wintertodt.config.WintertodtNotifyMode; @ConfigGroup("wintertodt") @@ -55,4 +56,18 @@ public interface WintertodtConfig extends Config { return Color.CYAN; } + + @ConfigItem( + position = 3, + keyName = "roundNotification", + name = "Wintertodt round notification", + description = "Notifies you before the round starts (in seconds)" + ) + @Range( + max = 60 + ) + default int roundNotification() + { + return 5; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java index 2360a68604..1fb36bfd27 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java @@ -56,10 +56,12 @@ import static net.runelite.api.ItemID.BRUMA_KINDLING; import static net.runelite.api.ItemID.BRUMA_ROOT; import net.runelite.api.MessageNode; import net.runelite.api.Player; +import net.runelite.api.Varbits; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.VarbitChanged; import net.runelite.client.Notifier; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; @@ -117,6 +119,8 @@ public class WintertodtPlugin extends Plugin private Instant lastActionTime; + private int previousTimerValue; + @Provides WintertodtConfig getConfig(ConfigManager configManager) { @@ -182,6 +186,30 @@ public class WintertodtPlugin extends Plugin checkActionTimeout(); } + @Subscribe + public void onVarbitChanged(VarbitChanged varbitChanged) + { + int timerValue = client.getVar(Varbits.WINTERTODT_TIMER); + if (timerValue != previousTimerValue) + { + int timeToNotify = config.roundNotification(); + if (timeToNotify > 0) + { + int timeInSeconds = timerValue * 30 / 50; + int prevTimeInSeconds = previousTimerValue * 30 / 50; + + log.debug("Seconds left until round start: {}", timeInSeconds); + + if (prevTimeInSeconds > timeToNotify && timeInSeconds <= timeToNotify) + { + notifier.notify("Wintertodt round is about to start"); + } + } + + previousTimerValue = timerValue; + } + } + private void checkActionTimeout() { if (currentActivity == WintertodtActivity.IDLE) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java new file mode 100644 index 0000000000..7069d4f06a --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019, Kusha Gharahi + * Copyright (c) 2019, Adam + * 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.wintertodt; + +import com.google.inject.Guice; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Varbits; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.Notifier; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.ui.overlay.OverlayManager; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class WintertodtPluginTest +{ + @Inject + WintertodtPlugin wintertodtPlugin; + + @Mock + @Bind + WintertodtConfig config; + + @Mock + @Bind + WintertodtOverlay wintertodtOverlay; + + @Mock + @Bind + OverlayManager overlayManager; + + @Mock + @Bind + ChatMessageManager chatMessageManager; + + @Mock + @Bind + Notifier notifier; + + @Mock + @Bind + Client client; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + } + + @Test + public void matchStartingNotification_shouldNotify_when15SecondsOptionSelected() + { + when(config.roundNotification()).thenReturn(15); + + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(35); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + //(15 * 50) / 30 = ~25 + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(25); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + + verify(notifier, times(1)).notify("Wintertodt round is about to start"); + } + + @Test + public void matchStartingNotification_shouldNotify_when10SecondsOptionSelected() + { + when(config.roundNotification()).thenReturn(10); + + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(20); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + //(10 * 50) / 30 = ~16 + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(16); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + + verify(notifier, times(1)).notify("Wintertodt round is about to start"); + } + + @Test + public void matchStartingNotification_shouldNotify_when5SecondsOptionSelected() + { + when(config.roundNotification()).thenReturn(5); + + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(10); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + //(5 * 50) / 30 = ~8 + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(8); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + + verify(notifier, times(1)).notify("Wintertodt round is about to start"); + } + + @Test + public void matchStartingNotification_shouldNotifyOnce() + { + when(config.roundNotification()).thenReturn(5); + + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(0); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(10); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(8); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(6); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(5); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(4); + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + + verify(notifier, times(1)).notify("Wintertodt round is about to start"); + } + + @Test + public void matchStartingNotification_shouldNotNotify_whenNoneOptionSelected() + { + when(config.roundNotification()).thenReturn(5); + when(client.getVar(Varbits.WINTERTODT_TIMER)).thenReturn(25); + + wintertodtPlugin.onVarbitChanged(new VarbitChanged()); + verify(notifier, times(0)).notify("Wintertodt round is about to start"); + } +}