From f3f2c7825c1f90e51941f7e927355036af4fb191 Mon Sep 17 00:00:00 2001 From: Alex Kolpa Date: Mon, 21 May 2018 16:42:04 +0200 Subject: [PATCH 1/2] Add agility arena notifier Notifies player when the active ticket dispenser has changed locations. --- .../client/plugins/agility/AgilityConfig.java | 11 +++++ .../client/plugins/agility/AgilityPlugin.java | 41 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java index 5ce0d3ed1e..20e0a0c0af 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java @@ -123,4 +123,15 @@ public interface AgilityConfig extends Config { return Color.RED; } + + @ConfigItem( + keyName = "agilityArenaNotifier", + name = "Agility Arena notifier", + description = "Notify on ticket location change in Agility Arena", + position = 9 + ) + default boolean notifyAgilityArena() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java index 5726ce12dd..9f4de5a058 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java @@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import javax.inject.Inject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -41,6 +42,7 @@ import net.runelite.api.Node; import static net.runelite.api.Skill.AGILITY; import net.runelite.api.Tile; import net.runelite.api.TileObject; +import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.DecorativeObjectChanged; import net.runelite.api.events.DecorativeObjectDespawned; import net.runelite.api.events.DecorativeObjectSpawned; @@ -49,6 +51,7 @@ import net.runelite.api.events.GameObjectChanged; import net.runelite.api.events.GameObjectDespawned; import net.runelite.api.events.GameObjectSpawned; import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.GroundObjectChanged; import net.runelite.api.events.GroundObjectDespawned; import net.runelite.api.events.GroundObjectSpawned; @@ -56,6 +59,7 @@ import net.runelite.api.events.ItemLayerChanged; import net.runelite.api.events.WallObjectChanged; import net.runelite.api.events.WallObjectDespawned; import net.runelite.api.events.WallObjectSpawned; +import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -67,6 +71,8 @@ import net.runelite.client.ui.overlay.Overlay; @Slf4j public class AgilityPlugin extends Plugin { + private static final int AGILITY_ARENA_REGION_ID = 11157; + @Getter private final Map obstacles = new HashMap<>(); @@ -80,6 +86,9 @@ public class AgilityPlugin extends Plugin @Inject private LapCounterOverlay lapOverlay; + @Inject + private Notifier notifier; + @Inject private Client client; @@ -90,6 +99,7 @@ public class AgilityPlugin extends Plugin private AgilitySession session; private int lastAgilityXp; + private WorldPoint lastArenaTicketPosition; @Provides AgilityConfig getConfig(ConfigManager configManager) @@ -119,11 +129,18 @@ public class AgilityPlugin extends Plugin case HOPPING: case LOGIN_SCREEN: session = null; + lastArenaTicketPosition = null; break; case LOADING: markOfGrace = null; obstacles.clear(); break; + case LOGGED_IN: + if (!isInAgilityArena()) + { + lastArenaTicketPosition = null; + } + break; } } @@ -204,6 +221,30 @@ public class AgilityPlugin extends Plugin return false; } + @Subscribe + public void onGameTick(GameTick tick) + { + if (isInAgilityArena()) + { + WorldPoint newTicketPosition = client.getHintArrowPoint(); + if (!Objects.equals(lastArenaTicketPosition, newTicketPosition)) + { + // We don't want to notify when players first enter the course + if (lastArenaTicketPosition != null && config.notifyAgilityArena()) + { + notifier.notify("Ticket location changed"); + } + + lastArenaTicketPosition = newTicketPosition; + } + } + } + + private boolean isInAgilityArena() + { + return AGILITY_ARENA_REGION_ID == client.getLocalPlayer().getWorldLocation().getRegionID(); + } + @Subscribe public void onGameObjectSpawned(GameObjectSpawned event) { From 58cf71bd05880926a47c5df3bfd9d14254f97706 Mon Sep 17 00:00:00 2001 From: Alex Kolpa Date: Mon, 21 May 2018 16:45:44 +0200 Subject: [PATCH 2/2] Add agility arena timer Add a timer infobox to show how long until the next ticket location change --- .../plugins/agility/AgilityArenaTimer.java | 66 ++++++++++++++++++ .../client/plugins/agility/AgilityConfig.java | 11 +++ .../client/plugins/agility/AgilityPlugin.java | 39 ++++++++++- .../plugins/agility/agilityarenaticket.png | Bin 0 -> 742 bytes 4 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java new file mode 100644 index 0000000000..3c6a493da5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityArenaTimer.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018, Alex Kolpa + * 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.agility; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.time.temporal.ChronoUnit; +import javax.imageio.ImageIO; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.infobox.Timer; + +@Slf4j +public class AgilityArenaTimer extends Timer +{ + public AgilityArenaTimer(Plugin plugin) + { + super(1, ChronoUnit.MINUTES, getTicketImage(), plugin); + setTooltip("Time left until location changes"); + } + + private static BufferedImage image; + private static BufferedImage getTicketImage() + { + if (image != null) + { + return image; + } + + try + { + synchronized (ImageIO.class) + { + image = ImageIO.read(AgilityArenaTimer.class.getResourceAsStream( "agilityarenaticket.png")); + } + } + catch (IOException ex) + { + log.warn("unable to load image", ex); + } + + return image; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java index 20e0a0c0af..55945fb4bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java @@ -134,4 +134,15 @@ public interface AgilityConfig extends Config { return true; } + + @ConfigItem( + keyName = "agilityArenaTimer", + name = "Agility Arena timer", + description = "Configures whether Agility Arena timer is displayed", + position = 10 + ) + default boolean showAgilityArenaTimer() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java index 9f4de5a058..bcf56162f8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java @@ -43,6 +43,7 @@ import static net.runelite.api.Skill.AGILITY; import net.runelite.api.Tile; import net.runelite.api.TileObject; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.DecorativeObjectChanged; import net.runelite.api.events.DecorativeObjectDespawned; import net.runelite.api.events.DecorativeObjectSpawned; @@ -64,6 +65,7 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; @PluginDescriptor( name = "Agility" @@ -92,6 +94,9 @@ public class AgilityPlugin extends Plugin @Inject private Client client; + @Inject + private InfoBoxManager infoBoxManager; + @Inject private AgilityConfig config; @@ -130,6 +135,7 @@ public class AgilityPlugin extends Plugin case LOGIN_SCREEN: session = null; lastArenaTicketPosition = null; + removeAgilityArenaTimer(); break; case LOADING: markOfGrace = null; @@ -139,11 +145,21 @@ public class AgilityPlugin extends Plugin if (!isInAgilityArena()) { lastArenaTicketPosition = null; + removeAgilityArenaTimer(); } break; } } + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!config.showAgilityArenaTimer()) + { + removeAgilityArenaTimer(); + } + } + @Subscribe public void onExperienceChanged(ExperienceChanged event) { @@ -230,9 +246,17 @@ public class AgilityPlugin extends Plugin if (!Objects.equals(lastArenaTicketPosition, newTicketPosition)) { // We don't want to notify when players first enter the course - if (lastArenaTicketPosition != null && config.notifyAgilityArena()) + if (lastArenaTicketPosition != null) { - notifier.notify("Ticket location changed"); + if (config.notifyAgilityArena()) + { + notifier.notify("Ticket location changed"); + } + + if (config.showAgilityArenaTimer()) + { + showNewAgilityArenaTimer(); + } } lastArenaTicketPosition = newTicketPosition; @@ -245,6 +269,17 @@ public class AgilityPlugin extends Plugin return AGILITY_ARENA_REGION_ID == client.getLocalPlayer().getWorldLocation().getRegionID(); } + private void removeAgilityArenaTimer() + { + infoBoxManager.removeIf(infoBox -> infoBox instanceof AgilityArenaTimer); + } + + private void showNewAgilityArenaTimer() + { + removeAgilityArenaTimer(); + infoBoxManager.addInfoBox(new AgilityArenaTimer(this)); + } + @Subscribe public void onGameObjectSpawned(GameObjectSpawned event) { diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png b/runelite-client/src/main/resources/net/runelite/client/plugins/agility/agilityarenaticket.png new file mode 100644 index 0000000000000000000000000000000000000000..55b841db979e8459bbcb8f056b6310fdf5ebc22f GIT binary patch literal 742 zcmVPx%ph-kQR7l6Ymd|PvQ543%$)s3?68i?Og)Ur(2qL)h1&mfuR5UJ>f=D)M#V9JR z8>RRMl(v#0h-B4;C z_sjuOhaHt|7|43CvTu!8WJwU(edy z{e1e#KCt`zeh3HeBw}#5a+w*-0%CzM;bQrD>imXE#W^~C*Q$%g#^Ptxm%sD`63Z~f zA+Txj;9)Q`D7?GpRvkZX7q(57;$9F7m<3FXnHx)~)H-q1=-t~X0Ko6>N31%3qFjmUNL~smLoYMN5&51B2E}A4D z5rbH8^Xjoko3qvKq}a@kJbO^GdF=-TfXzl5T8Gt4YY+<>o(m>IZS^Bk{vjNBGIyaT z5CAqdTkw4aB8Ji$^=8h3qE6=1R*@v2?`t$Y1>aZjm4P-UR3)gbez2ec8nbS-5AU1- zg%&m%Z8SZFR;wLrVH_+2Gyqr1#V%Nqg&DiS`1ti_6P~a7S~yzh27w8gU_*8L!*=<9 Y0aVq-g_Ue2?EnA(07*qoM6N<$f-~z=f&c&j literal 0 HcmV?d00001