Plugin: Hydra Helper Plugin, Refactoring + Features (#2186)

Plugin: Hydra Helper Plugin, Refactoring + Features
This commit is contained in:
Owain van Brakel
2020-01-29 12:41:25 +01:00
committed by GitHub
17 changed files with 1104 additions and 576 deletions

View File

@@ -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)

View File

@@ -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",

View File

@@ -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();

View File

@@ -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;

View File

@@ -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<LocalPoint, Projectile> 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;

View File

@@ -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<LocalPoint, Projectile> 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<WorldPoint> fountainWorldPoint = WorldPoint.toLocalInstance(client, hydra.getPhase().getFountain()); // thanks
if (fountainWorldPoint.size() > 1) // for

View File

@@ -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;
}
}

View File

@@ -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<Integer, Integer> hydras = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<Integer, Integer> 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();
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020, Dutta64 <https://github.com/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();
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2020, Dutta64 <https://github.com/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();
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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<Integer, Hydra> 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);
}
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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 <b>bold</b>.<br>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.<br>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;
}

View File

@@ -0,0 +1,421 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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<HydraAnimation> 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<Integer, Hydra> hydras = new HashMap<>();
private final Map<LocalPoint, Projectile> 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 <https://github.com/lucwousin>
*
* @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 <https://github.com/lucwousin>
*/
private void updatePoisonProjectiles()
{
final Set<LocalPoint> expiredPoisonProjectiles = new HashSet<>();
for (final Map.Entry<LocalPoint, Projectile> 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;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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<LocalPoint, Projectile> 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 <https://github.com/lucwousin>
*
* @param graphics graphics object
* @param poisonProjectiles poisonProjectiles object
*/
private void drawPoisonArea(final Graphics2D graphics, final Map<LocalPoint, Projectile> poisonProjectiles)
{
final Area poisonTiles = new Area();
for (final Map.Entry<LocalPoint, Projectile> 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);
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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<Integer, Hydra> 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);
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2018, https://openosrs.com
* Copyright (c) 2020, Dutta64 <https://github.com/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<Integer, Hydra> 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);
}
}