From 2aeea8efc28f3a7c2253ec95e6cce9eecb09b4b1 Mon Sep 17 00:00:00 2001 From: Dutta64 <38548565+dutta64@users.noreply.github.com> Date: Fri, 3 Jan 2020 01:18:25 -0700 Subject: [PATCH] Plugin: Hydra Helper Plugin * Refactoring * Add poison overlay * Add InteractingChanged event subscription to handle already-spawned npcs * Rename BabyHydra classes to 'Hydra' Plugin: Rename AlchemicalHydra plugin class files to prevent conflicts PR changes --- .../{Hydra.java => AlchemicalHydra.java} | 16 +- ...Config.java => AlchemicalHydraConfig.java} | 2 +- ...erlay.java => AlchemicalHydraOverlay.java} | 14 +- ...raPhase.java => AlchemicalHydraPhase.java} | 4 +- ...Plugin.java => AlchemicalHydraPlugin.java} | 32 +- ....java => AlchemicalHydraSceneOverlay.java} | 10 +- .../plugins/hydra/BabyHydraOverlay.java | 118 ----- .../client/plugins/hydra/BabyHydraPlugin.java | 253 ----------- .../plugins/hydra/BabyHydraPrayOverlay.java | 137 ------ .../runelite/client/plugins/hydra/Hydra.java | 73 +++ .../client/plugins/hydra/HydraAnimation.java | 61 +++ .../hydra/HydraAttackCounterOverlay.java | 171 +++++++ ...{BabyHydraConfig.java => HydraConfig.java} | 38 +- .../client/plugins/hydra/HydraPlugin.java | 421 ++++++++++++++++++ .../plugins/hydra/HydraPoisonOverlay.java | 111 +++++ ...a => HydraPrayerAttackCounterOverlay.java} | 52 ++- .../plugins/hydra/HydraPrayerOverlay.java | 167 +++++++ 17 files changed, 1104 insertions(+), 576 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{Hydra.java => AlchemicalHydra.java} (89%) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{HydraConfig.java => AlchemicalHydraConfig.java} (98%) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{HydraOverlay.java => AlchemicalHydraOverlay.java} (93%) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{HydraPhase.java => AlchemicalHydraPhase.java} (94%) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{HydraPlugin.java => AlchemicalHydraPlugin.java} (91%) rename runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/{HydraSceneOverlay.java => AlchemicalHydraSceneOverlay.java} (93%) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraOverlay.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPlugin.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPrayOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/Hydra.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAnimation.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAttackCounterOverlay.java rename runelite-client/src/main/java/net/runelite/client/plugins/hydra/{BabyHydraConfig.java => HydraConfig.java} (64%) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPoisonOverlay.java rename runelite-client/src/main/java/net/runelite/client/plugins/hydra/{BabyHydraIndicatorOverlay.java => HydraPrayerAttackCounterOverlay.java} (63%) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerOverlay.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/Hydra.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydra.java similarity index 89% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/Hydra.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydra.java index 3b332f3589..97782f5c8a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/Hydra.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydra.java @@ -40,7 +40,7 @@ import net.runelite.client.util.ImageUtil; @Getter(AccessLevel.PACKAGE) @RequiredArgsConstructor @Singleton -class Hydra +class AlchemicalHydra { @Getter(AccessLevel.PACKAGE) @RequiredArgsConstructor @@ -61,7 +61,7 @@ class Hydra if (image == null) { BufferedImage tmp = spriteManager.getSprite(spriteID, 0); - image = tmp == null ? null : ImageUtil.resizeImage(tmp, HydraOverlay.IMGSIZE, HydraOverlay.IMGSIZE); + image = tmp == null ? null : ImageUtil.resizeImage(tmp, AlchemicalHydraOverlay.IMGSIZE, AlchemicalHydraOverlay.IMGSIZE); } return image; @@ -70,7 +70,7 @@ class Hydra private final NPC npc; - private HydraPhase phase = HydraPhase.ONE; + private AlchemicalHydraPhase phase = AlchemicalHydraPhase.ONE; private int attackCount = 0; private int nextSwitch = phase.getAttacksPerSwitch(); @@ -84,14 +84,14 @@ class Hydra @Setter(AccessLevel.PACKAGE) private boolean weakened = false; - void changePhase(HydraPhase newPhase) + void changePhase(AlchemicalHydraPhase newPhase) { phase = newPhase; nextSpecial = 3; attackCount = 0; weakened = false; - if (newPhase == HydraPhase.FOUR) + if (newPhase == AlchemicalHydraPhase.FOUR) { weakened = true; switchStyles(); @@ -101,9 +101,9 @@ class Hydra private void switchStyles() { - nextAttack = lastAttack == Hydra.AttackStyle.MAGIC - ? Hydra.AttackStyle.RANGED - : Hydra.AttackStyle.MAGIC; + nextAttack = lastAttack == AlchemicalHydra.AttackStyle.MAGIC + ? AlchemicalHydra.AttackStyle.RANGED + : AlchemicalHydra.AttackStyle.MAGIC; } void handleAttack(int id) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraConfig.java similarity index 98% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraConfig.java index 4cf308f3e7..90ac1350cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraConfig.java @@ -32,7 +32,7 @@ import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigSection; @ConfigGroup("betterHydra") -public interface HydraConfig extends Config +public interface AlchemicalHydraConfig extends Config { @ConfigSection( keyName = "features", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraOverlay.java similarity index 93% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraOverlay.java index 38572c9ee2..e844f897b3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraOverlay.java @@ -47,11 +47,11 @@ import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.util.ImageUtil; @Singleton -class HydraOverlay extends Overlay +class AlchemicalHydraOverlay extends Overlay { static final int IMGSIZE = 36; - private final HydraPlugin plugin; + private final AlchemicalHydraPlugin plugin; private final Client client; private final SpriteManager spriteManager; private final PanelComponent panelComponent = new PanelComponent(); @@ -71,7 +71,7 @@ class HydraOverlay extends Overlay private int stunTicks; @Inject - HydraOverlay(final HydraPlugin plugin, final Client client, final SpriteManager spriteManager) + AlchemicalHydraOverlay(final AlchemicalHydraPlugin plugin, final Client client, final SpriteManager spriteManager) { this.plugin = plugin; this.client = client; @@ -83,7 +83,7 @@ class HydraOverlay extends Overlay @Override public Dimension render(Graphics2D graphics2D) { - final Hydra hydra = plugin.getHydra(); + final AlchemicalHydra hydra = plugin.getHydra(); panelComponent.getChildren().clear(); if (hydra == null) @@ -125,9 +125,9 @@ class HydraOverlay extends Overlay panelComponent.getChildren().add(stunComponent); } - private void addSpecOverlay(final Hydra hydra) + private void addSpecOverlay(final AlchemicalHydra hydra) { - final HydraPhase phase = hydra.getPhase(); + final AlchemicalHydraPhase phase = hydra.getPhase(); final int nextSpec = hydra.getNextSpecialRelative(); if (nextSpec > 3) @@ -152,7 +152,7 @@ class HydraOverlay extends Overlay panelComponent.getChildren().add(specComponent); } - private void addPrayOverlay(final Hydra hydra) + private void addPrayOverlay(final AlchemicalHydra hydra) { final Prayer nextPrayer = hydra.getNextAttack().getPrayer(); final int nextSwitch = hydra.getNextSwitch(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPhase.java similarity index 94% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPhase.java index 4fa739e6d8..97e577d6ef 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPhase.java @@ -37,7 +37,7 @@ import net.runelite.client.util.ImageUtil; @Getter(AccessLevel.PACKAGE) @RequiredArgsConstructor -enum HydraPhase +enum AlchemicalHydraPhase { ONE(3, AnimationID.HYDRA_1_1, AnimationID.HYDRA_1_2, ProjectileID.HYDRA_POISON, 0, SpriteID.BIG_ASS_GUTHIX_SPELL, new WorldPoint(1371, 10263, 0)), TWO(3, AnimationID.HYDRA_2_1, AnimationID.HYDRA_2_2, 0, AnimationID.HYDRA_LIGHTNING, SpriteID.BIG_SPEC_TRANSFER, new WorldPoint(1371, 10272, 0)), @@ -61,7 +61,7 @@ enum HydraPhase if (specImage == null) { BufferedImage tmp = spriteManager.getSprite(specImageID, 0); - specImage = tmp == null ? null : ImageUtil.resizeImage(tmp, HydraOverlay.IMGSIZE, HydraOverlay.IMGSIZE); + specImage = tmp == null ? null : ImageUtil.resizeImage(tmp, AlchemicalHydraOverlay.IMGSIZE, AlchemicalHydraOverlay.IMGSIZE); } return specImage; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPlugin.java similarity index 91% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPlugin.java index 39f0cf3a52..c51dde9e2d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraPlugin.java @@ -56,7 +56,7 @@ import net.runelite.client.events.ConfigChanged; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.alchemicalhydra.Hydra.AttackStyle; +import net.runelite.client.plugins.alchemicalhydra.AlchemicalHydra.AttackStyle; import net.runelite.client.ui.overlay.OverlayManager; @PluginDescriptor( @@ -68,7 +68,7 @@ import net.runelite.client.ui.overlay.OverlayManager; ) @Slf4j @Singleton -public class HydraPlugin extends Plugin +public class AlchemicalHydraPlugin extends Plugin { private static final int[] HYDRA_REGIONS = { 5279, 5280, @@ -80,7 +80,7 @@ public class HydraPlugin extends Plugin private Map poisonProjectiles = new HashMap<>(); @Getter(AccessLevel.PACKAGE) - private Hydra hydra; + private AlchemicalHydra hydra; @Getter(AccessLevel.PACKAGE) private boolean counting; @@ -101,21 +101,21 @@ public class HydraPlugin extends Plugin private EventBus eventBus; @Inject - private HydraConfig config; + private AlchemicalHydraConfig config; @Inject - private HydraOverlay overlay; + private AlchemicalHydraOverlay overlay; @Inject - private HydraSceneOverlay sceneOverlay; + private AlchemicalHydraSceneOverlay sceneOverlay; @Inject private OverlayManager overlayManager; @Provides - HydraConfig provideConfig(ConfigManager configManager) + AlchemicalHydraConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(HydraConfig.class); + return configManager.getConfig(AlchemicalHydraConfig.class); } @Override @@ -235,7 +235,7 @@ public class HydraPlugin extends Plugin { if (npc.getId() == NpcID.ALCHEMICAL_HYDRA) { - hydra = new Hydra(npc); + hydra = new AlchemicalHydra(npc); addFightSubscriptions(); break; } @@ -252,7 +252,7 @@ public class HydraPlugin extends Plugin } eventBus.unregister("npcSpawned"); - hydra = new Hydra(event.getNpc()); + hydra = new AlchemicalHydra(event.getNpc()); addFightSubscriptions(); addOverlays(); } @@ -266,23 +266,23 @@ public class HydraPlugin extends Plugin return; } - HydraPhase phase = hydra.getPhase(); + AlchemicalHydraPhase phase = hydra.getPhase(); if (actor.getAnimation() == phase.getDeathAnim2() && - phase != HydraPhase.THREE // Else log's gonna say "Tried some weird shit" + phase != AlchemicalHydraPhase.THREE // Else log's gonna say "Tried some weird shit" || actor.getAnimation() == phase.getDeathAnim1() && - phase == HydraPhase.THREE) // We want the pray to switch ye ok ty + phase == AlchemicalHydraPhase.THREE) // We want the pray to switch ye ok ty { switch (phase) { case ONE: - hydra.changePhase(HydraPhase.TWO); + hydra.changePhase(AlchemicalHydraPhase.TWO); return; case TWO: - hydra.changePhase(HydraPhase.THREE); + hydra.changePhase(AlchemicalHydraPhase.THREE); return; case THREE: - hydra.changePhase(HydraPhase.FOUR); + hydra.changePhase(AlchemicalHydraPhase.FOUR); return; case FOUR: hydra = null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraSceneOverlay.java similarity index 93% rename from runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraSceneOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraSceneOverlay.java index 257bf9f6b6..71e24470b8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/AlchemicalHydraSceneOverlay.java @@ -47,7 +47,7 @@ import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @Singleton -class HydraSceneOverlay extends Overlay +class AlchemicalHydraSceneOverlay extends Overlay { @Setter(AccessLevel.PACKAGE) private Color poisonBorder; @@ -61,11 +61,11 @@ class HydraSceneOverlay extends Overlay @Setter(AccessLevel.PACKAGE) private Color badFountain; - private final HydraPlugin plugin; + private final AlchemicalHydraPlugin plugin; private final Client client; @Inject - public HydraSceneOverlay(final Client client, final HydraPlugin plugin) + public AlchemicalHydraSceneOverlay(final Client client, final AlchemicalHydraPlugin plugin) { setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.UNDER_WIDGETS); @@ -76,7 +76,7 @@ class HydraSceneOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - Hydra hydra = plugin.getHydra(); + AlchemicalHydra hydra = plugin.getHydra(); final Map poisonProjectiles = plugin.getPoisonProjectiles(); if (plugin.isCounting() && !poisonProjectiles.isEmpty()) @@ -119,7 +119,7 @@ class HydraSceneOverlay extends Overlay graphics.fill(poisonTiles); } - private void drawFountain(Graphics2D graphics, Hydra hydra) + private void drawFountain(Graphics2D graphics, AlchemicalHydra hydra) { Collection fountainWorldPoint = WorldPoint.toLocalInstance(client, hydra.getPhase().getFountain()); // thanks if (fountainWorldPoint.size() > 1) // for diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraOverlay.java deleted file mode 100644 index c252ec0949..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraOverlay.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2018, https://openosrs.com - * 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.hydra; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import javax.inject.Singleton; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.Point; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; - -@Singleton -public class BabyHydraOverlay extends Overlay -{ - private final BabyHydraPlugin plugin; - - @Inject - private Client client; - - @Inject - private BabyHydraOverlay(final BabyHydraPlugin plugin) - { - this.plugin = plugin; - setLayer(OverlayLayer.ABOVE_SCENE); - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.MED); - } - - @Override - public Dimension render(Graphics2D graphics) - { - for (NPC hydra : client.getNpcs()) - { - if (hydra == null || hydra.getName() == null) - { - continue; - } - if (hydra.getName().equalsIgnoreCase("Hydra") && plugin.getHydras().containsKey(hydra.getIndex())) - { - int val = plugin.getHydras().get(hydra.getIndex()); - if (val != 0) - { - if (plugin.isBoldText()) - { - graphics.setFont(FontManager.getRunescapeBoldFont()); - } - if (plugin.getHydraattacks().containsKey(hydra.getIndex())) - { - int attack = plugin.getHydraattacks().get(hydra.getIndex()); - - Point textLocation = hydra.getCanvasTextLocation(graphics, "TEMP!!", hydra.getLogicalHeight() + 100); - - if (textLocation != null && attack == 8261) - { - if (val == 3) - { - OverlayUtil.renderTextLocation(graphics, textLocation, "MAGE", Color.BLUE); - } - else - { - OverlayUtil.renderTextLocation(graphics, textLocation, "RANGE", Color.GREEN); - } - } - else if (textLocation != null && attack == 8262) - { - if (val == 3) - { - OverlayUtil.renderTextLocation(graphics, textLocation, "RANGE", Color.GREEN); - } - else - { - OverlayUtil.renderTextLocation(graphics, textLocation, "MAGE", Color.BLUE); - } - } - } - Point hydraPoint = hydra.getCanvasTextLocation(graphics, Integer.toString(val), hydra.getLogicalHeight() + 40); - if (hydraPoint != null) - { - OverlayUtil.renderTextLocation(graphics, hydraPoint, Integer.toString(val), Color.WHITE); - } - } - } - - } - graphics.setFont(FontManager.getRunescapeFont()); - return null; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPlugin.java deleted file mode 100644 index dc063bdcc3..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPlugin.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2018, https://openosrs.com - * 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.hydra; - -import com.google.inject.Provides; -import java.util.HashMap; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import lombok.AccessLevel; -import lombok.Getter; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.events.AnimationChanged; -import net.runelite.api.events.NpcDespawned; -import net.runelite.api.events.NpcSpawned; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.ConfigChanged; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Hydra Helper", - description = "Overlays for small hydras", - tags = {"Hydra", "Helper", "you", "probably", "want", "the", "other", "one"}, - type = PluginType.PVM, - enabledByDefault = false -) -@Singleton -public class BabyHydraPlugin extends Plugin -{ - @Inject - private OverlayManager overlayManager; - - @Inject - private BabyHydraConfig config; - - @Inject - private BabyHydraOverlay hydraOverlay; - - @Inject - private BabyHydraPrayOverlay hydraPrayOverlay; - - @Inject - private BabyHydraIndicatorOverlay hydraIndicatorOverlay; - - @Inject - private Client client; - - @Provides - BabyHydraConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(BabyHydraConfig.class); - } - - @Getter(AccessLevel.PACKAGE) - private Map hydras = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private Map hydraattacks = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private NPC hydra; - - private boolean TextIndicator; - @Getter(AccessLevel.PACKAGE) - private boolean BoldText; - private boolean PrayerHelper; - - @Override - protected void startUp() - { - updateConfig(); - - if (this.TextIndicator) - { - overlayManager.add(hydraOverlay); - } - if (this.PrayerHelper) - { - overlayManager.add(hydraPrayOverlay); - overlayManager.add(hydraIndicatorOverlay); - } - } - - @Override - protected void shutDown() - { - overlayManager.remove(hydraOverlay); - overlayManager.remove(hydraPrayOverlay); - overlayManager.remove(hydraIndicatorOverlay); - hydras.clear(); - hydraattacks.clear(); - } - - @Subscribe - private void onConfigChanged(ConfigChanged event) - { - if (!event.getGroup().equals("hydra")) - { - return; - } - - updateConfig(); - - if (event.getKey().equals("textindicators")) - { - if (Boolean.parseBoolean(event.getNewValue())) - { - overlayManager.add(hydraOverlay); - } - else - { - overlayManager.remove(hydraOverlay); - } - } - else if (event.getKey().equals("prayerhelper")) - { - if (Boolean.parseBoolean(event.getNewValue())) - { - overlayManager.add(hydraPrayOverlay); - overlayManager.add(hydraIndicatorOverlay); - } - else - { - overlayManager.remove(hydraPrayOverlay); - overlayManager.remove(hydraIndicatorOverlay); - } - } - } - - @Subscribe - private void onNpcSpawned(NpcSpawned event) - { - NPC hydra = event.getNpc(); - if (hydra.getCombatLevel() != 0 && hydra.getName() != null && hydra.getName().equalsIgnoreCase("Hydra") && !hydras.containsKey(hydra.getIndex())) - { - hydras.put(hydra.getIndex(), 3); - } - } - - @Subscribe - private void onNpcDespawned(NpcDespawned event) - { - NPC hydra = event.getNpc(); - if (hydra.getCombatLevel() != 0 && hydra.getName() != null && hydra.getName().equalsIgnoreCase("Hydra")) - { - hydras.remove(hydra.getIndex()); - hydraattacks.remove(hydra.getIndex()); - } - } - - @Subscribe - private void onAnimationChanged(AnimationChanged event) - { - Actor monster = event.getActor(); - Actor local = client.getLocalPlayer(); - if (!(monster instanceof NPC) || local == null) - { - return; - } - NPC hydra = (NPC) monster; - - if (hydra.getCombatLevel() == 0 || hydra.getName() == null) - { - return; - } - - if (!hydra.getName().equalsIgnoreCase("Hydra") || !hydras.containsKey(hydra.getIndex())) - { - return; - } - - if (hydra.getAnimation() != 8261 && hydra.getAnimation() != 8262) - { - return; - } - - if (hydra.getInteracting() != null && hydra.getInteracting() == local) - { - this.hydra = hydra; - } - - if (hydraattacks.containsKey(hydra.getIndex())) - { - int lastattack = hydraattacks.get(hydra.getIndex()); - hydraattacks.replace(hydra.getIndex(), hydra.getAnimation()); - - if (lastattack != hydra.getAnimation()) - { - hydras.replace(hydra.getIndex(), 2); - } - else - { - int currval = hydras.get(hydra.getIndex()); - if (currval == 1) - { - hydras.replace(hydra.getIndex(), 3); - } - else - { - hydras.replace(hydra.getIndex(), currval - 1); - } - } - } - else - { - hydraattacks.put(hydra.getIndex(), hydra.getAnimation()); - int currval = hydras.get(hydra.getIndex()); - if (currval == 1) - { - hydras.replace(hydra.getIndex(), 3); - } - else - { - hydras.replace(hydra.getIndex(), currval - 1); - } - } - } - - private void updateConfig() - { - this.TextIndicator = config.TextIndicator(); - this.BoldText = config.BoldText(); - this.PrayerHelper = config.PrayerHelper(); - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPrayOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPrayOverlay.java deleted file mode 100644 index 67b5703bb7..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraPrayOverlay.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2018, https://openosrs.com - * 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.hydra; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import javax.inject.Singleton; -import net.runelite.api.Client; -import net.runelite.api.Prayer; -import net.runelite.api.SpriteID; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.ComponentConstants; -import net.runelite.client.ui.overlay.components.ImageComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; - -@Singleton -public class BabyHydraPrayOverlay extends Overlay -{ - private final BabyHydraPlugin plugin; - - private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150); - private BufferedImage prayMage; - private BufferedImage prayRanged; - private final PanelComponent imagePanelComponent = new PanelComponent(); - - @Inject - private SpriteManager spriteManager; - - @Inject - private Client client; - - @Inject - private BabyHydraPrayOverlay(final BabyHydraPlugin plugin, final SpriteManager spriteManager) - { - this.plugin = plugin; - this.spriteManager = spriteManager; - setPosition(OverlayPosition.BOTTOM_RIGHT); - setPriority(OverlayPriority.HIGH); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (prayMage == null) - { - prayMage = spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MAGIC, 0); - } - if (prayRanged == null) - { - prayRanged = spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MISSILES, 0); - } - - if (plugin.getHydra() != null && plugin.getHydras().containsKey(plugin.getHydra().getIndex())) - { - int val = plugin.getHydras().get(plugin.getHydra().getIndex()); - if (val != 0 && plugin.getHydraattacks().containsKey(plugin.getHydra().getIndex())) - { - int attack = plugin.getHydraattacks().get(plugin.getHydra().getIndex()); - if (attack == 8261) - { - if (val == 3) - { - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayMage)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MAGIC) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); - - return imagePanelComponent.render(graphics); - } - else - { - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayRanged)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MISSILES) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); - - return imagePanelComponent.render(graphics); - } - } - else if (attack == 8262) - { - if (val == 3) - { - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayRanged)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MISSILES) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); - - return imagePanelComponent.render(graphics); - } - else - { - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayMage)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MAGIC) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); - - return imagePanelComponent.render(graphics); - } - } - } - } - return null; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/Hydra.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/Hydra.java new file mode 100644 index 0000000000..e1540682a9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/Hydra.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import java.awt.Graphics2D; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.NPC; +import net.runelite.api.Point; + +public class Hydra +{ + static final int MAX_ATTACK_COUNT = 3; + + private final NPC npc; + + @Getter(AccessLevel.PACKAGE) + private int attackCount; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private HydraAnimation hydraAnimation; + + public Hydra(final NPC npc) + { + this.npc = npc; + this.attackCount = MAX_ATTACK_COUNT; + this.hydraAnimation = null; + } + + void updateAttackCount() + { + attackCount = attackCount == 1 ? MAX_ATTACK_COUNT : --attackCount; + } + + void resetAttackCount() + { + attackCount = MAX_ATTACK_COUNT; + } + + Point getCanvasTextLocation(final Graphics2D graphics, final String text, final int zOffset) + { + return npc.getCanvasTextLocation(graphics, text, zOffset); + } + + int getLogicalHeight() + { + return npc.getLogicalHeight(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAnimation.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAnimation.java new file mode 100644 index 0000000000..05f4bc6f3a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAnimation.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import java.awt.Color; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum HydraAnimation +{ + RANGE(8261, "RANGE", new Color(0, 255, 0)), + MAGIC(8262, "MAGIC", new Color(52, 152, 219)), + POISON(8263, "POISON", new Color(255, 0, 0)); // Not used currently + + @Getter(AccessLevel.PACKAGE) + private final int id; + + @Getter(AccessLevel.PACKAGE) + private final String text; + + @Getter(AccessLevel.PACKAGE) + private final Color color; + + public static HydraAnimation fromId(final int id) + { + for (final HydraAnimation hydraAnimation : HydraAnimation.values()) + { + if (Objects.equals(hydraAnimation.id, id)) + { + return hydraAnimation; + } + } + + throw new IllegalArgumentException(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAttackCounterOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAttackCounterOverlay.java new file mode 100644 index 0000000000..da429d5976 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraAttackCounterOverlay.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.AccessLevel; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Point; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +@Singleton +public class HydraAttackCounterOverlay extends Overlay +{ + private final HydraPlugin hydraPlugin; + + private final Client client; + + @Setter(AccessLevel.PACKAGE) + private Map hydras; + + @Setter(AccessLevel.PACKAGE) + private boolean isBoldAttackCounterOverlay; + + @Inject + private HydraAttackCounterOverlay(final HydraPlugin hydraPlugin, final Client client) + { + this.hydraPlugin = hydraPlugin; + this.client = client; + this.hydras = new HashMap<>(); + this.isBoldAttackCounterOverlay = false; + setLayer(OverlayLayer.ABOVE_SCENE); + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.MED); + } + + @Override + public Dimension render(final Graphics2D graphics) + { + if (!hydraPlugin.isPlayerAtHydraRegion()) + { + return null; + } + + for (final NPC npc : client.getNpcs()) + { + final Hydra hydra = hydras.get(npc.getIndex()); + + if (hydra == null) + { + continue; + } + + if (isBoldAttackCounterOverlay) + { + graphics.setFont(FontManager.getRunescapeBoldFont()); + } + else + { + graphics.setFont(FontManager.getRunescapeFont()); + } + + renderAnimationAttackType(graphics, hydra); + renderAttackCount(graphics, hydra); + } + + return null; + } + + private void renderAnimationAttackType(final Graphics2D graphics, final Hydra hydra) + { + final HydraAnimation hydraAnimation = hydra.getHydraAnimation(); + + if (hydraAnimation == null) + { + return; + } + + final int heightOffset = 100; + + final Point textLocation = hydra.getCanvasTextLocation(graphics, "TEMP!", + hydra.getLogicalHeight() + heightOffset); + + if (textLocation == null) + { + return; + } + + final boolean attackCountIsMax = hydra.getAttackCount() == Hydra.MAX_ATTACK_COUNT; + + switch (hydraAnimation) + { + case RANGE: + if (attackCountIsMax) + { + OverlayUtil.renderTextLocation(graphics, textLocation, HydraAnimation.MAGIC.getText(), + HydraAnimation.MAGIC.getColor()); + } + else + { + OverlayUtil.renderTextLocation(graphics, textLocation, HydraAnimation.RANGE.getText(), + HydraAnimation.RANGE.getColor()); + } + break; + case MAGIC: + if (attackCountIsMax) + { + OverlayUtil.renderTextLocation(graphics, textLocation, HydraAnimation.RANGE.getText(), + HydraAnimation.RANGE.getColor()); + } + else + { + OverlayUtil.renderTextLocation(graphics, textLocation, HydraAnimation.MAGIC.getText(), + HydraAnimation.MAGIC.getColor()); + } + break; + default: + break; + } + } + + private void renderAttackCount(final Graphics2D graphics, final Hydra hydra) + { + final int attackCount = hydra.getAttackCount(); + + final int heightOffset = 30; + + final Point textLocation = hydra.getCanvasTextLocation(graphics, Integer.toString(attackCount), + hydra.getLogicalHeight() + heightOffset); + + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, Integer.toString(attackCount), Color.WHITE); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraConfig.java similarity index 64% rename from runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraConfig.java rename to runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraConfig.java index a92a3789ea..9733fbfcf3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraConfig.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,38 +30,49 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @ConfigGroup("hydra") -public interface BabyHydraConfig extends Config +public interface HydraConfig extends Config { @ConfigItem( position = 1, - keyName = "textindicators", - name = "Text Indicator", - description = "Configures if text indicator is shown above hydra's or not." + keyName = "attackCounterOverlay", + name = "Attack Counter Overlay", + description = "Configures if an attack counter overlay is shown." ) - default boolean TextIndicator() + default boolean isAttackCounterOverlay() { return true; } @ConfigItem( position = 2, - keyName = "countersize", - name = "Bold indicator", - description = "Configures if text indicator is bold or not." + keyName = "boldAttackCounterOverlay", + name = "Bold Attack Counter", + description = "Configures if the attack counter is bold.
Attack Counter Overlay must be enabled." ) - default boolean BoldText() + default boolean isBoldAttackCounterOverlay() { return false; } @ConfigItem( position = 3, - keyName = "prayerhelper", - name = "Prayer Helper", - description = "Configures if prayer helper is shown or not." + keyName = "prayerOverlay", + name = "Prayer Overlay", + description = "Configures if a prayer overlay is shown.
This overlay includes a mini attack counter." ) - default boolean PrayerHelper() + default boolean isPrayerOverlay() + { + return true; + } + + @ConfigItem( + position = 4, + keyName = "poisonProjectileOverlay", + name = "Poison Projectile Overlay", + description = "Configures if a poison projectile overlay is shown." + ) + default boolean isPoisonOverlay() { return true; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java new file mode 100644 index 0000000000..eef36dff89 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import com.google.inject.Provides; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Player; +import net.runelite.api.Projectile; +import net.runelite.api.ProjectileID; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.AnimationChanged; +import net.runelite.api.events.InteractingChanged; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.ProjectileMoved; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Hydra Helper", + description = "Overlays for normal Hydras.", + tags = {"hydra", "helper", "baby", "small", "normal", "regular"}, + type = PluginType.PVM, + enabledByDefault = false +) +@Slf4j +@Singleton +public class HydraPlugin extends Plugin +{ + static final Set VALID_HYDRA_ANIMATIONS = EnumSet.of( + HydraAnimation.RANGE, + HydraAnimation.MAGIC + ); + + private static final String CONFIG_GROUP_NAME = "hydra"; + private static final String CONFIG_ITEM_ATTACK_COUNTER = "attackCounterOverlay"; + private static final String CONFIG_ITEM_PRAYER_OVERLAY = "prayerOverlay"; + private static final String CONFIG_ITEM_POISON_PROJECTILE_OVERLAY = "poisonProjectileOverlay"; + private static final String CONFIG_ITEM_BOLD_ATTACK_COUNTER_OVERLAY = "boldAttackCounterOverlay"; + + private static final String NPC_NAME_HYDRA = "Hydra"; + + private static final int HYDRA_REGION_1 = 5279; + private static final int HYDRA_REGION_2 = 5280; + + @Inject + private Client client; + + @Inject + private HydraConfig hydraConfig; + + @Inject + private OverlayManager overlayManager; + + @Inject + private HydraAttackCounterOverlay hydraAttackCounterOverlay; + + @Inject + private HydraPrayerOverlay hydraPrayerOverlay; + + @Inject + private HydraPrayerAttackCounterOverlay hydraPrayerAttackCounterOverlay; + + @Inject + private HydraPoisonOverlay hydraPoisonOverlay; + + private final Map hydras = new HashMap<>(); + + private final Map poisonProjectiles = new HashMap<>(); + + @Getter(AccessLevel.PACKAGE) + private NPC interactingNpc = null; + + @Provides + HydraConfig provideConfig(final ConfigManager configManager) + { + return configManager.getConfig(HydraConfig.class); + } + + @Override + protected void startUp() + { + if (hydraConfig.isAttackCounterOverlay()) + { + overlayManager.add(hydraAttackCounterOverlay); + } + + if (hydraConfig.isPrayerOverlay()) + { + overlayManager.add(hydraPrayerOverlay); + overlayManager.add(hydraPrayerAttackCounterOverlay); + } + + if (hydraConfig.isPoisonOverlay()) + { + overlayManager.add(hydraPoisonOverlay); + } + + hydraAttackCounterOverlay.setBoldAttackCounterOverlay(hydraConfig.isBoldAttackCounterOverlay()); + + hydraAttackCounterOverlay.setHydras(hydras); + hydraPrayerOverlay.setHydras(hydras); + hydraPrayerAttackCounterOverlay.setHydras(hydras); + + hydraPoisonOverlay.setPoisonProjectiles(poisonProjectiles); + + resetHydras(); + poisonProjectiles.clear(); + } + + @Override + protected void shutDown() + { + overlayManager.remove(hydraAttackCounterOverlay); + overlayManager.remove(hydraPrayerOverlay); + overlayManager.remove(hydraPrayerAttackCounterOverlay); + overlayManager.remove(hydraPoisonOverlay); + resetHydras(); + poisonProjectiles.clear(); + + } + + @Subscribe + private void onConfigChanged(final ConfigChanged event) + { + if (!event.getGroup().equals(CONFIG_GROUP_NAME)) + { + return; + } + + final boolean newConfigValue = Boolean.parseBoolean(event.getNewValue()); + + switch (event.getKey()) + { + case CONFIG_ITEM_ATTACK_COUNTER: + if (newConfigValue) + { + overlayManager.add(hydraAttackCounterOverlay); + } + else + { + overlayManager.remove(hydraAttackCounterOverlay); + } + break; + case CONFIG_ITEM_PRAYER_OVERLAY: + if (newConfigValue) + { + overlayManager.add(hydraPrayerOverlay); + overlayManager.add(hydraPrayerAttackCounterOverlay); + } + else + { + overlayManager.remove(hydraPrayerOverlay); + overlayManager.remove(hydraPrayerAttackCounterOverlay); + } + break; + case CONFIG_ITEM_POISON_PROJECTILE_OVERLAY: + if (newConfigValue) + { + overlayManager.add(hydraPoisonOverlay); + } + else + { + overlayManager.remove(hydraPoisonOverlay); + } + break; + case CONFIG_ITEM_BOLD_ATTACK_COUNTER_OVERLAY: + hydraAttackCounterOverlay.setBoldAttackCounterOverlay(hydraConfig.isBoldAttackCounterOverlay()); + break; + default: + break; + } + } + + @Subscribe + private void onNpcSpawned(final NpcSpawned event) + { + final NPC npc = event.getNpc(); + + if (isActorHydra(npc)) + { + addHydra(npc); + } + } + + @Subscribe + private void onNpcDespawned(final NpcDespawned event) + { + final NPC npc = event.getNpc(); + + if (isActorHydra(npc)) + { + removeHydra(npc); + poisonProjectiles.clear(); + } + } + + @Subscribe + private void onInteractingChanged(final InteractingChanged event) + { + final Actor source = event.getSource(); + + if (!isActorHydra(source)) + { + return; + } + + final NPC npc = (NPC) source; + + addHydra(npc); + updateInteractingNpc(npc); + } + + @Subscribe + private void onAnimationChanged(final AnimationChanged event) + { + final Actor actor = event.getActor(); + + if (!isActorHydra(actor)) + { + return; + } + + final NPC npc = (NPC) event.getActor(); + + addHydra(npc); + updateInteractingNpc(npc); + + HydraAnimation hydraAnimation; + + try + { + hydraAnimation = HydraAnimation.fromId(npc.getAnimation()); + } + catch (final IllegalArgumentException e) + { + hydraAnimation = null; + } + + if (hydraAnimation == null || !VALID_HYDRA_ANIMATIONS.contains(hydraAnimation)) + { + // If the animation is not range/magic then do nothing. + return; + } + + final Hydra hydra = hydras.get(npc.getIndex()); + + if (hydra.getHydraAnimation() == null) + { + // If this is the first observed animation then set it + hydra.setHydraAnimation(hydraAnimation); + } + else + { + if (!Objects.equals(hydra.getHydraAnimation(), hydraAnimation)) + { + // If the animation switched from range/magic then set it and reset attack count + hydra.setHydraAnimation(hydraAnimation); + hydra.resetAttackCount(); + } + } + + hydra.updateAttackCount(); + + if (!poisonProjectiles.isEmpty()) + { + updatePoisonProjectiles(); + } + } + + /** + * See net.runelite.client.plugins.alchemicalhydra.AlchemicalHydraPlugin + * Copyright (c) 2019, Lucas + * + * @param event event object + */ + @Subscribe + private void onProjectileMoved(final ProjectileMoved event) + { + if (interactingNpc == null || client.getGameCycle() >= event.getProjectile().getStartMovementCycle()) + { + return; + } + + final Projectile projectile = event.getProjectile(); + + final int projectileId = projectile.getId(); + + if (projectileId == ProjectileID.HYDRA_POISON) + { + poisonProjectiles.put(event.getPosition(), projectile); + } + } + + /** + * See net.runelite.client.plugins.alchemicalhydra.AlchemicalHydraPlugin + * Copyright (c) 2019, Lucas + */ + private void updatePoisonProjectiles() + { + final Set expiredPoisonProjectiles = new HashSet<>(); + + for (final Map.Entry entry : poisonProjectiles.entrySet()) + { + if (entry.getValue().getEndCycle() < client.getGameCycle()) + { + expiredPoisonProjectiles.add(entry.getKey()); + } + } + + for (final LocalPoint projectileLocalPoint : expiredPoisonProjectiles) + { + poisonProjectiles.remove(projectileLocalPoint); + } + } + + boolean isPlayerAtHydraRegion() + { + final Player player = client.getLocalPlayer(); + + if (player == null) + { + return false; + } + + final WorldPoint worldPoint = player.getWorldLocation(); + + if (worldPoint == null) + { + return false; + } + + final int regionId = worldPoint.getRegionID(); + + return regionId == HYDRA_REGION_1 || regionId == HYDRA_REGION_2; + } + + private static boolean isActorHydra(final Actor actor) + { + return Objects.equals(actor.getName(), NPC_NAME_HYDRA); + } + + private void updateInteractingNpc(final NPC npc) + { + if (!Objects.equals(interactingNpc, npc) && + Objects.equals(npc.getInteracting(), client.getLocalPlayer())) + { + interactingNpc = npc; + } + } + + private void addHydra(final NPC npc) + { + final int npcIndex = npc.getIndex(); + + if (!hydras.containsKey(npcIndex)) + { + hydras.put(npcIndex, new Hydra(npc)); + } + } + + private void removeHydra(final NPC npc) + { + final int npcIndex = npc.getIndex(); + + hydras.remove(npcIndex); + + if (Objects.equals(interactingNpc, npc)) + { + interactingNpc = null; + } + } + + private void resetHydras() + { + hydras.clear(); + interactingNpc = null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPoisonOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPoisonOverlay.java new file mode 100644 index 0000000000..847f4af5df --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPoisonOverlay.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.geom.Area; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.AccessLevel; +import lombok.Setter; +import net.runelite.api.Client; +import static net.runelite.api.Perspective.getCanvasTileAreaPoly; +import net.runelite.api.Projectile; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +@Singleton +public class HydraPoisonOverlay extends Overlay +{ + private static final Color poisonBorder = new Color(255, 0, 0, 100);; + private static final Color poisonFill = new Color(255, 0, 0, 50);; + + private final Client client; + + @Setter(AccessLevel.PACKAGE) + private Map poisonProjectiles; + + @Inject + public HydraPoisonOverlay(final Client client) + { + this.client = client; + this.poisonProjectiles = new HashMap<>(); + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.UNDER_WIDGETS); + } + + @Override + public Dimension render(final Graphics2D graphics) + { + if (!poisonProjectiles.isEmpty()) + { + drawPoisonArea(graphics, poisonProjectiles); + } + + return null; + } + + /** + * See net.runelite.client.plugins.alchemicalhydra.AlchemicalHydraSceneOverlay + * Copyright (c) 2019, Lucas + * + * @param graphics graphics object + * @param poisonProjectiles poisonProjectiles object + */ + private void drawPoisonArea(final Graphics2D graphics, final Map poisonProjectiles) + { + final Area poisonTiles = new Area(); + + for (final Map.Entry entry : poisonProjectiles.entrySet()) + { + if (entry.getValue().getEndCycle() < client.getGameCycle()) + { + continue; + } + + final LocalPoint point = entry.getKey(); + final Polygon poly = getCanvasTileAreaPoly(client, point, 3); + + if (poly != null) + { + poisonTiles.add(new Area(poly)); + } + } + + graphics.setPaintMode(); + graphics.setColor(poisonBorder); + graphics.draw(poisonTiles); + graphics.setColor(poisonFill); + graphics.fill(poisonTiles); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraIndicatorOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerAttackCounterOverlay.java similarity index 63% rename from runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraIndicatorOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerAttackCounterOverlay.java index 6d87a08567..54075f119f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/BabyHydraIndicatorOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerAttackCounterOverlay.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,8 +27,13 @@ package net.runelite.client.plugins.hydra; import java.awt.Dimension; import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.Map; import javax.inject.Inject; import javax.inject.Singleton; +import lombok.AccessLevel; +import lombok.Setter; +import net.runelite.api.NPC; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; @@ -35,34 +41,48 @@ import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @Singleton -public class BabyHydraIndicatorOverlay extends Overlay +public class HydraPrayerAttackCounterOverlay extends Overlay { - private final BabyHydraPlugin plugin; + private final HydraPlugin hydraPlugin; - private final PanelComponent panelComponent = new PanelComponent(); + private final PanelComponent panelComponent; + + @Setter(AccessLevel.PACKAGE) + private Map hydras; @Inject - private BabyHydraIndicatorOverlay(final BabyHydraPlugin plugin) + private HydraPrayerAttackCounterOverlay(final HydraPlugin hydraPlugin) { - this.plugin = plugin; + this.hydraPlugin = hydraPlugin; + this.panelComponent = new PanelComponent(); + this.panelComponent.setPreferredSize(new Dimension(14, 0)); + this.hydras = new HashMap<>(); setPosition(OverlayPosition.BOTTOM_RIGHT); setPriority(OverlayPriority.MED); - panelComponent.setPreferredSize(new Dimension(14, 0)); } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(final Graphics2D graphics) { - if (plugin.getHydra() != null && plugin.getHydras().containsKey(plugin.getHydra().getIndex())) + final NPC npc = hydraPlugin.getInteractingNpc(); + + if (npc == null) { - int val = plugin.getHydras().get(plugin.getHydra().getIndex()); - if (val != 0) - { - panelComponent.getChildren().clear(); - panelComponent.getChildren().add(LineComponent.builder().right(Integer.toString(val)).build()); - return panelComponent.render(graphics); - } + return null; } - return null; + + final Hydra hydra = hydras.get(npc.getIndex()); + + if (hydra == null) + { + return null; + } + + final String attackCount = String.valueOf(hydra.getAttackCount()); + + panelComponent.getChildren().clear(); + panelComponent.getChildren().add(LineComponent.builder().right(attackCount).build()); + + return panelComponent.render(graphics); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerOverlay.java new file mode 100644 index 0000000000..c74fdb1ad4 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPrayerOverlay.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018, https://openosrs.com + * Copyright (c) 2020, Dutta64 + * 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.hydra; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.AccessLevel; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Prayer; +import net.runelite.api.SpriteID; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.ImageComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +@Singleton +public class HydraPrayerOverlay extends Overlay +{ + private static final Color ACTIVATED_BACKGROUND_COLOR = new Color(0, 150, 0, 150); + private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150); + + private final HydraPlugin hydraPlugin; + + private final Client client; + + private final SpriteManager spriteManager; + + private final PanelComponent panelComponent; + + @Setter(AccessLevel.PACKAGE) + private Map hydras; + + private BufferedImage bufferedImageRange; + private BufferedImage bufferedImageMagic; + + @Inject + private HydraPrayerOverlay(final HydraPlugin hydraPlugin, final Client client, final SpriteManager spriteManager) + { + this.hydraPlugin = hydraPlugin; + this.client = client; + this.spriteManager = spriteManager; + this.panelComponent = new PanelComponent(); + this.hydras = new HashMap<>(); + this.bufferedImageRange = null; + this.bufferedImageMagic = null; + setPosition(OverlayPosition.BOTTOM_RIGHT); + setPriority(OverlayPriority.HIGH); + } + + @Override + public Dimension render(final Graphics2D graphics) + { + final NPC npc = hydraPlugin.getInteractingNpc(); + + if (npc == null) + { + return null; + } + + final Hydra hydra = hydras.get(npc.getIndex()); + + if (hydra == null) + { + return null; + } + + final HydraAnimation hydraAnimation = hydra.getHydraAnimation(); + + if (hydraAnimation == null || !HydraPlugin.VALID_HYDRA_ANIMATIONS.contains(hydraAnimation)) + { + return null; + } + + if (bufferedImageMagic == null) + { + bufferedImageMagic = spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MAGIC, 0); + } + + if (bufferedImageRange == null) + { + bufferedImageRange = spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MISSILES, 0); + } + + final boolean attackCountIsMax = hydra.getAttackCount() == Hydra.MAX_ATTACK_COUNT; + + switch (hydraAnimation) + { + case RANGE: + if (attackCountIsMax) + { + return renderPanelMagic(graphics); + } + else + { + return renderPanelRange(graphics); + } + case MAGIC: + if (attackCountIsMax) + { + return renderPanelRange(graphics); + } + else + { + return renderPanelMagic(graphics); + } + default: + break; + } + + return null; + } + + private Dimension renderPanelMagic(final Graphics2D graphics) + { + panelComponent.getChildren().clear(); + panelComponent.getChildren().add(new ImageComponent(bufferedImageMagic)); + panelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MAGIC) + ? ACTIVATED_BACKGROUND_COLOR + : NOT_ACTIVATED_BACKGROUND_COLOR); + + return panelComponent.render(graphics); + } + + private Dimension renderPanelRange(final Graphics2D graphics) + { + panelComponent.getChildren().clear(); + panelComponent.getChildren().add(new ImageComponent(bufferedImageRange)); + panelComponent.setBackgroundColor(client.isPrayerActive(Prayer.PROTECT_FROM_MISSILES) + ? ACTIVATED_BACKGROUND_COLOR + : NOT_ACTIVATED_BACKGROUND_COLOR); + + return panelComponent.render(graphics); + } +}