gauntlet: redesign (#1200)

* gauntlet

* .

* Update GauntletOverlay.java

* Update GauntletUtils.java

* gauntlet: Update, streamline, optimize, and refactor.

* Various Fixes

* Fix player attack incrementing.

* Actually fix player attack incrementing this time. :3head:

* Revert "Actually fix player attack incrementing this time. :3head:"

This reverts commit eaa12234

* Fix double increment bug.

* Various Refactoring and updates.

* Add sound back in

* Update projectile api with proper name

* Format Config, add Widget helper, and cleanup access.

* Update GauntletPlugin.java

* Update GauntletOverlay.java

* Update GauntletOverlay.java

* Update GauntletConfig.java

* Update GauntletPlugin.java

* Update GauntletTimer.java

* Update GauntletTimer.java

* Update GauntletTimer.java

* Update GauntletTimer.java

* Fixup widget helper.

* Use varbits instead of hidden.

* Fixup prayer overlay.

* gauntlet: include tick timers, and various fixes.

* gauntlet: various fixes, and qol changes.

* gauntlet: give each tornado their own ticks, and show true location.

* gauntlet: hunllef spelling fixes

* Update ProjectileID.java
This commit is contained in:
Kyleeld
2019-08-01 12:35:23 +01:00
committed by GitHub
parent bcc75c1e94
commit 64af016b99
14 changed files with 1660 additions and 365 deletions

View File

@@ -102,11 +102,12 @@ public class ProjectileID
public static final int HYDRA_LIGHTNING_2 = 1665;
public static final int DRAKE_BREATH = 1637;
public static final int HUNLEFF_MAGE_ATTACK = 1707;
public static final int HUNLEFF_CORRUPTED_MAGE_ATTACK = 1708;
public static final int HUNLEFF_RANGE_ATTACK = 1711;
public static final int HUNLEFF_CORRUPTED_RANGE_ATTACK = 1712;
public static final int HUNLLEF_MAGE_ATTACK = 1707;
public static final int HUNLLEF_CORRUPTED_MAGE_ATTACK = 1708;
public static final int HUNLLEF_RANGE_ATTACK = 1711;
public static final int HUNLLEF_CORRUPTED_RANGE_ATTACK = 1712;
public static final int HUNLLEF_PRAYER_ATTACK = 1713;
public static final int HUNLLEF_CORRUPTED_PRAYER_ATTACK = 1714;
public static final int ZALCANO_PROJECTILE = 1728;
}

View File

@@ -692,7 +692,12 @@ public enum Varbits
/**
* 1 is true, 0 is false.
*/
GAUNTLET_FINAL_ROOM_ENTERED(9177);
GAUNTLET_FINAL_ROOM_ENTERED(9177),
/**
* 1 is true, 0 is false.
*/
GAUNTLET_ENTERED(9178);
/**
* The raw varbit ID.

View File

@@ -37,13 +37,13 @@ import net.runelite.api.Client;
import net.runelite.api.DecorativeObject;
import net.runelite.api.GameObject;
import net.runelite.api.GroundObject;
import net.runelite.api.TileItemPile;
import net.runelite.api.MainBufferProvider;
import net.runelite.api.Model;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.Perspective;
import net.runelite.api.Player;
import net.runelite.api.TileItemPile;
import net.runelite.api.TileObject;
import net.runelite.api.WallObject;
import net.runelite.api.coords.LocalPoint;
@@ -968,7 +968,7 @@ public class ModelOutlineRenderer
}
}
private void drawOutline(GameObject gameObject, int outlineWidth, Color innerColor, Color outerColor)
public void drawOutline(GameObject gameObject, int outlineWidth, Color innerColor, Color outerColor)
{
LocalPoint lp = gameObject.getLocalLocation();
if (lp != null)
@@ -979,7 +979,7 @@ public class ModelOutlineRenderer
}
}
private void drawOutline(GroundObject groundObject, int outlineWidth, Color innerColor, Color outerColor)
public void drawOutline(GroundObject groundObject, int outlineWidth, Color innerColor, Color outerColor)
{
LocalPoint lp = groundObject.getLocalLocation();
if (lp != null)

View File

@@ -0,0 +1,272 @@
/*
* THIS SOFTWARE WRITTEN BY A KEYBOARD-WIELDING MONKEY BOI
* No rights reserved. Use, redistribute, and modify at your own discretion,
* and in accordance with Yagex and RuneLite guidelines.
* However, aforementioned monkey would prefer if you don't sell this plugin for profit.
* Good luck on your raids!
*/
package net.runelite.client.plugins.gauntlet;
import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Range;
import net.runelite.client.config.Stub;
@ConfigGroup("Gauntlet")
public interface GauntletConfig extends Config
{
@ConfigItem(
position = 0,
keyName = "resources",
name = "Resources",
description = ""
)
default Stub resources()
{
return new Stub();
}
@ConfigItem(
position = 1,
keyName = "highlightResources",
name = "Highlight Resources",
description = "Highlights all the resources in each room with a color.",
parent = "resources"
)
default boolean highlightResources()
{
return true;
}
@ConfigItem(
position = 2,
keyName = "highlightResourcesColor",
name = "Highlight Color",
description = "Highlights all the resources in each room with this color.",
parent = "resources",
hidden = true,
unhide = "highlightResources"
)
default Color highlightResourcesColor()
{
return Color.YELLOW;
}
@ConfigItem(
position = 3,
keyName = "highlightResourcesIcons",
name = "Highlight Resources with an Icon",
description = "Highlights all the icons in each room with an icon.",
parent = "resources",
hidden = true,
unhide = "highlightResources"
)
default boolean highlightResourcesIcons()
{
return true;
}
@Range(
min = 1,
max = 50
)
@ConfigItem(
position = 4,
keyName = "resourceIconSize",
name = "Resource Icon Size",
description = " change the size of resource icons.",
hidden = true,
unhide = "highlightResources",
parent = "resources"
)
default int resourceIconSize()
{
return 20;
}
@ConfigItem(
position = 5,
keyName = "boss",
name = "Boss",
description = ""
)
default Stub boss()
{
return new Stub();
}
@ConfigItem(
position = 6,
keyName = "countBossAttacks",
name = "Count Boss Attacks",
description = "Count the attacks until the boss switches their style.",
parent = "boss"
)
default boolean countBossAttacks()
{
return true;
}
@ConfigItem(
position = 7,
keyName = "countPlayerAttacks",
name = "Count Player Attacks",
description = "Count the player attacks until the boss switches their prayer.",
parent = "boss"
)
default boolean countPlayerAttacks()
{
return true;
}
@ConfigItem(
position = 8,
keyName = "highlightWidget",
name = "Highlight Correct Prayer",
description = "Highlights correct prayer in your prayer book.",
parent = "boss"
)
default boolean highlightWidget()
{
return true;
}
@ConfigItem(
position = 8,
keyName = "flashOnWrongAttack",
name = "Flash on Wrong Attack",
description = "This will flash your screen if you attack with the wrong stlye.",
parent = "boss"
)
default boolean flashOnWrongAttack()
{
return true;
}
@ConfigItem(
position = 9,
keyName = "uniquePrayerAudio",
name = "Unique Prayer Audio",
description = "Plays a unique sound whenever the boss is about to shut down your prayer.",
parent = "boss"
)
default boolean uniquePrayerAudio()
{
return true;
}
@ConfigItem(
position = 10,
keyName = "uniquePrayerVisual",
name = "Unique Prayer Visual",
description = "Prayer attacks will have a unique overlay visual.",
parent = "boss"
)
default boolean uniquePrayerVisual()
{
return true;
}
@ConfigItem(
position = 11,
keyName = "uniqueAttackVisual",
name = "Unique Magic & Range Visuals",
description = "Magic and Range attacks will have a unique overlay visual.",
parent = "boss"
)
default boolean uniqueAttackVisual()
{
return false;
}
@ConfigItem(
position = 12,
keyName = "overlayBoss",
name = "Overlay the Boss (Color)",
description = "Overlay the boss with an color denoting it's current attack style.",
parent = "boss"
)
default boolean overlayBoss()
{
return true;
}
@ConfigItem(
position = 13,
keyName = "overlayBossPrayer",
name = "Overlay the Boss (Icon)",
description = "Overlay the boss with an icon denoting it's current attack style.",
parent = "boss"
)
default boolean overlayBossPrayer()
{
return false;
}
@ConfigItem(
position = 14,
keyName = "overlayTornadoes",
name = "Show Tornado Decay",
description = "Display the amount of ticks left until the tornadoes decay.",
parent = "boss"
)
default boolean overlayTornadoes()
{
return true;
}
@Range(
min = 1,
max = 50
)
@ConfigItem(
position = 15,
keyName = "projectileIconSize",
name = "Boss Projectile Icon Size",
description = " change the size of Projectile icons.",
parent = "boss"
)
default int projectileIconSize()
{
return 20;
}
@ConfigItem(
position = 16,
keyName = "timer",
name = "Timer",
description = ""
)
default Stub timer()
{
return new Stub();
}
@ConfigItem(
position = 17,
keyName = "displayTimerWidget",
name = "Show Custom Timer (Widget)",
description = "Display a timer widget that tracks your gauntlet progress.",
parent = "timer"
)
default boolean displayTimerWidget()
{
return true;
}
@ConfigItem(
position = 18,
keyName = "displayTimerChat",
name = "Show Custom Timer (Chat)",
description = "Display a chat message that tracks your gauntlet progress.",
parent = "timer"
)
default boolean displayTimerChat()
{
return true;
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
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.PanelComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
import net.runelite.client.ui.overlay.components.table.TableAlignment;
import net.runelite.client.ui.overlay.components.table.TableComponent;
import net.runelite.client.util.ColorUtil;
@Singleton
@Slf4j
public class GauntletCounter extends Overlay
{
private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150);
private final GauntletPlugin plugin;
private final PanelComponent panelComponent = new PanelComponent();
@Inject
GauntletCounter(final GauntletPlugin plugin)
{
this.plugin = plugin;
setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT);
setPriority(OverlayPriority.HIGH);
}
@Override
public Dimension render(Graphics2D graphics)
{
panelComponent.getChildren().clear();
if (plugin.getHunllef() == null || !plugin.isInRoom())
{
return null;
}
panelComponent.getChildren().add(TitleComponent.builder()
.text("Hunllef")
.color(Color.pink)
.build());
Color color = plugin.getPlayerAttacks() == 1 ? Color.RED : Color.WHITE;
final String pHits = ColorUtil.prependColorTag(Integer.toString(plugin.getPlayerAttacks()), color);
TableComponent tableComponent = new TableComponent();
tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT);
tableComponent.addRow("Hunllef Hits: ", Integer.toString(plugin.getAttacks()));
tableComponent.addRow("Player Hits Left: ", pHits);
panelComponent.getChildren().add(tableComponent);
return panelComponent.render(graphics);
}
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
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.InfoBoxComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@Singleton
@Slf4j
public class GauntletInfoBox extends Overlay
{
private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150);
private final Client client;
private final GauntletPlugin plugin;
private final PanelComponent panelComponent = new PanelComponent();
private final SpriteManager spriteManager;
@Inject
GauntletInfoBox(final @Nullable Client client, final GauntletPlugin plugin, final SpriteManager spriteManager)
{
this.client = client;
this.plugin = plugin;
this.spriteManager = spriteManager;
setPosition(OverlayPosition.BOTTOM_RIGHT);
setPriority(OverlayPriority.HIGH);
}
@Override
public Dimension render(Graphics2D graphics)
{
panelComponent.getChildren().clear();
if (plugin.getHunllef() == null || !plugin.isInRoom())
{
return null;
}
Prayer prayer = plugin.getNextPrayer();
if (prayer == null)
{
return null;
}
InfoBoxComponent prayComponent = new InfoBoxComponent();
BufferedImage prayImg = scaleImg(getPrayerImage(prayer));
prayComponent.setImage(prayImg);
prayComponent.setColor(Color.WHITE);
prayComponent.setBackgroundColor(client.isPrayerActive(prayer)
? ComponentConstants.STANDARD_BACKGROUND_COLOR
: NOT_ACTIVATED_BACKGROUND_COLOR);
prayComponent.setPreferredSize(new Dimension(40, 40));
panelComponent.getChildren().add(prayComponent);
panelComponent.setPreferredSize(new Dimension(40, 40));
panelComponent.setBorder(new Rectangle(0, 0, 0, 0));
return panelComponent.render(graphics);
}
private BufferedImage getPrayerImage(Prayer prayer)
{
switch (prayer)
{
case PROTECT_FROM_MAGIC:
return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MAGIC, 0);
case PROTECT_FROM_MELEE:
return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MELEE, 0);
case PROTECT_FROM_MISSILES:
return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MISSILES, 0);
}
return null;
}
private static BufferedImage scaleImg(final BufferedImage img)
{
if (img == null)
{
return null;
}
final double width = img.getWidth(null);
final double height = img.getHeight(null);
final double size = 36; // Limit size to 2 as that is minimum size not causing breakage
final double scalex = size / width;
final double scaley = size / height;
final double scale = Math.min(scalex, scaley);
final int newWidth = (int) (width * scale);
final int newHeight = (int) (height * scale);
final BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
final Graphics g = scaledImage.createGraphics();
g.drawImage(img, 0, 0, newWidth, newHeight, null);
g.dispose();
return scaledImage;
}
}

View File

@@ -0,0 +1,416 @@
/*
* Copyright (c) 2019, kThisIsCvpv <https://github.com/kThisIsCvpv>
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.Model;
import net.runelite.api.NPC;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Projectile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.model.Jarvis;
import net.runelite.api.model.Vertex;
import net.runelite.client.graphics.ModelOutlineRenderer;
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;
import static net.runelite.client.util.ImageUtil.resizeImage;
public class GauntletOverlay extends Overlay
{
private static final Color FLASH_COLOR = new Color(255, 0, 0, 70);
private static final int MAX_DISTANCE = 2400;
private final Client client;
private final GauntletPlugin plugin;
private final ModelOutlineRenderer outlineRenderer;
private int timeout;
@Inject
private GauntletOverlay(Client client, GauntletPlugin plugin, ModelOutlineRenderer outlineRenderer)
{
this.client = client;
this.plugin = plugin;
this.outlineRenderer = outlineRenderer;
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGH);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
}
@Override
public Dimension render(Graphics2D graphics)
{
// Save resources. There's nothing to render if the user is not in a raid.
if (!plugin.startedGauntlet())
{
return null;
}
if (plugin.fightingBoss())
{
// This section handles the visuals when the player is in the boss room.
// This section handles the projectile overlays.
Set<Missiles> projectiles = plugin.getProjectiles();
projectiles.forEach(projectile ->
{
BufferedImage icon = resizeImage(projectile.getImage(), plugin.getProjectileIconSize(), plugin.getProjectileIconSize());
Color color = projectile.getColor();
Polygon polygon = boundProjectile(projectile.getProjectile());
if (polygon == null)
{
int x = (int) projectile.getProjectile().getX();
int y = (int) projectile.getProjectile().getY();
LocalPoint point = new LocalPoint(x, y);
Point loc = Perspective.getCanvasImageLocation(client, point, icon, -(int) projectile.getProjectile().getZ());
if (loc == null)
{
return;
}
if (plugin.isUniqueAttackVisual())
{
graphics.drawImage(icon, loc.getX(), loc.getY(), null);
}
}
else
{
graphics.setColor(color);
graphics.draw(polygon);
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 50));
graphics.fill(polygon);
if (plugin.isUniqueAttackVisual())
{
Rectangle bounds = polygon.getBounds();
int x = (int) bounds.getCenterX() - (icon.getWidth() / 2);
int y = (int) bounds.getCenterY() - (icon.getHeight() / 2);
graphics.drawImage(icon, x, y, null);
}
}
});
projectiles.removeIf(proj -> proj.getProjectile().getRemainingCycles() <= 0);
plugin.getTornadoes().forEach(tornado ->
{
if (plugin.isOverlayTornadoes())
{
if (tornado.getTimeLeft() <= 0)
{
return;
}
final String textOverlay = Integer.toString(tornado.getTimeLeft());
final Point textLoc = Perspective.getCanvasTextLocation(client, graphics, tornado.getNpc().getLocalLocation(), textOverlay, 0);
final LocalPoint lp = LocalPoint.fromWorld(client, tornado.getNpc().getWorldLocation());
if (lp == null)
{
return;
}
final Polygon tilePoly = Perspective.getCanvasTilePoly(client, lp);
OverlayUtil.renderPolygon(graphics, tilePoly, Color.YELLOW);
if (textLoc == null)
{
return;
}
Font oldFont = graphics.getFont();
graphics.setFont(new Font("Arial", Font.BOLD, 20));
Point pointShadow = new Point(textLoc.getX() + 1, textLoc.getY() + 1);
OverlayUtil.renderTextLocation(graphics, pointShadow, textOverlay, Color.BLACK);
OverlayUtil.renderTextLocation(graphics, textLoc, textOverlay, Color.YELLOW);
graphics.setFont(oldFont);
}
});
if (plugin.getHunllef() != null)
{
final Hunllef hunllef = plugin.getHunllef();
final Hunllef.BossAttackPhase phase = hunllef.getCurrentPhase();
final NPC boss = hunllef.getNpc();
final LocalPoint point = boss.getLocalLocation();
if (plugin.isFlash())
{
final Color flash = graphics.getColor();
graphics.setColor(FLASH_COLOR);
graphics.fill(new Rectangle(client.getCanvas().getSize()));
graphics.setColor(flash);
timeout++;
if (timeout >= 15)
{
timeout = 0;
plugin.setFlash(false);
}
}
if (plugin.isOverlayBoss())
{
Polygon polygon = boss.getConvexHull();
if (polygon == null)
{
return null;
}
if (phase.getPrayer() != null && !client.isPrayerActive(phase.getPrayer()))
{
Color color = phase.getColor();
outlineRenderer.drawOutline(boss, 12, color, new Color(0, 0, 0, 0));
}
}
if (plugin.isOverlayBossPrayer())
{
BufferedImage attackIcon = null;
switch (phase)
{
case MAGIC:
attackIcon = resizeImage(hunllef.getMage(), plugin.getProjectileIconSize(), plugin.getProjectileIconSize());
break;
case RANGE:
attackIcon = resizeImage(hunllef.getRange(), plugin.getProjectileIconSize(), plugin.getProjectileIconSize());
break;
default:
break;
}
if (attackIcon == null)
{
return null;
}
Point imageLoc = Perspective.getCanvasImageLocation(client, point, attackIcon, boss.getLogicalHeight() / 2);
if (imageLoc == null)
{
return null;
}
graphics.drawImage(attackIcon, imageLoc.getX(), imageLoc.getY(), null);
}
if (plugin.isHighlightWidget())
{
if (phase.getPrayer() == null)
{
return null;
}
final Rectangle bounds = OverlayUtil.renderPrayerOverlay(graphics, client, phase.getPrayer(), phase.getColor());
if (bounds != null)
{
final Color color = hunllef.getTicksUntilAttack() == 1 ? Color.WHITE : phase.getColor();
renderTextLocation(graphics, Integer.toString(hunllef.getTicksUntilAttack()), 16, Font.BOLD, color, centerPoint(bounds), false);
}
}
// This section handles any text overlays.
String textOverlay = "";
// Handles the counter for the boss.
if (plugin.isCountBossAttacks())
{
textOverlay = Integer.toString(hunllef.getBossAttacks());
}
// Handles the counter for the player.
if (plugin.isCountPlayerAttacks())
{
if (textOverlay.length() > 0)
{
textOverlay += " | ";
}
textOverlay += Integer.toString(hunllef.getPlayerAttacks());
}
// Handles drawing the text onto the boss.
if (textOverlay.length() > 0)
{
Point textLoc = Perspective.getCanvasTextLocation(client, graphics, point, textOverlay, boss.getLogicalHeight() / 2);
if (textLoc == null)
{
return null;
}
textLoc = new Point(textLoc.getX(), textLoc.getY() + 35);
Font oldFont = graphics.getFont();
graphics.setFont(new Font("Arial", Font.BOLD, 20));
Point pointShadow = new Point(textLoc.getX() + 1, textLoc.getY() + 1);
OverlayUtil.renderTextLocation(graphics, pointShadow, textOverlay, Color.BLACK);
OverlayUtil.renderTextLocation(graphics, textLoc, textOverlay, phase.getColor());
graphics.setFont(oldFont);
}
}
}
else
{
// This section overlays all resources.
final LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation();
final Set<Resources> resources = plugin.getResources();
resources.forEach(object ->
{
if (object.getGameObject().getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE)
{
// Don't use Convex Hull click box. As the room start to fill up, your FPS will dip.
Polygon polygon = object.getGameObject().getConvexHull();
if (polygon == null)
{
return;
}
// This section will highlight the resource with color.
if (plugin.isHighlightResources())
{
outlineRenderer.drawOutline(object.getGameObject(), 2, plugin.getHighlightResourcesColor());
}
// This section will overlay the resource with an icon.
if (plugin.isHighlightResourcesIcons())
{
BufferedImage icon = resizeImage(object.getImage(), plugin.getResourceIconSize(), plugin.getResourceIconSize());
if (icon != null)
{
Rectangle bounds = polygon.getBounds();
int startX = (int) bounds.getCenterX() - (icon.getWidth() / 2);
int startY = (int) bounds.getCenterY() - (icon.getHeight() / 2);
graphics.drawImage(icon, startX, startY, null);
}
}
}
});
}
return null;
}
private Polygon boundProjectile(Projectile proj)
{
if (proj == null || proj.getModel() == null)
{
return null;
}
Model model = proj.getModel();
LocalPoint point = new LocalPoint((int) proj.getX(), (int) proj.getY());
int tileHeight = Perspective.getTileHeight(client, point, client.getPlane());
double angle = Math.atan(proj.getVelocityY() / proj.getVelocityX());
angle = Math.toDegrees(angle) + (proj.getVelocityX() < 0 ? 180 : 0);
angle = angle < 0 ? angle + 360 : angle;
angle = 360 - angle - 90;
double ori = angle * (512d / 90d);
ori = ori < 0 ? ori + 2048 : ori;
int orientation = (int) Math.round(ori);
List<Vertex> vertices = model.getVertices();
for (int i = 0; i < vertices.size(); ++i)
{
vertices.set(i, vertices.get(i).rotate(orientation));
}
List<Point> list = new ArrayList<>();
for (Vertex vertex : vertices)
{
final Point localToCanvas = Perspective.localToCanvas(client, point.getX() - vertex.getX(), point.getY() - vertex.getZ(), tileHeight + vertex.getY() + (int) proj.getZ());
if (localToCanvas != null)
{
list.add(localToCanvas);
}
}
final List<Point> convexHull = Jarvis.convexHull(list);
if (convexHull == null)
{
return null;
}
final Polygon polygon = new Polygon();
for (final Point hullPoint : convexHull)
{
polygon.addPoint(hullPoint.getX(), hullPoint.getY());
}
return polygon;
}
private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint, boolean shadows)
{
graphics.setFont(new Font("Arial", fontStyle, fontSize));
if (canvasPoint != null)
{
final Point canvasCenterPoint = new Point(
canvasPoint.getX() - 3,
canvasPoint.getY() + 6);
final Point canvasCenterPoint_shadow = new Point(
canvasPoint.getX() - 2,
canvasPoint.getY() + 7);
if (shadows)
{
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK);
}
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor);
}
}
private Point centerPoint(Rectangle rect)
{
int x = (int) (rect.getX() + rect.getWidth() / 2);
int y = (int) (rect.getY() + rect.getHeight() / 2);
return new Point(x, y);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, xperiaclash <https://github.com/xperiaclash>
* Copyright (c) 2019, kThisIsCvpv <https://github.com/kThisIsCvpv>
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* All rights reserved.
*
@@ -22,244 +22,430 @@
* (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.gauntlet;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provides;
import java.awt.Color;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.GameObject;
import net.runelite.api.GameState;
import net.runelite.api.HeadIcon;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.Prayer;
import net.runelite.api.NpcID;
import net.runelite.api.ObjectID;
import net.runelite.api.Player;
import net.runelite.api.Projectile;
import net.runelite.api.ProjectileID;
import net.runelite.api.SoundEffectID;
import net.runelite.api.Varbits;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.ProjectileSpawned;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.LIGHTNING;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.MAGIC;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.PRAYER;
import static net.runelite.client.plugins.gauntlet.Hunllef.BossAttack.RANGE;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
name = "Gauntlet Boss Helper",
description = "Prayer Overlay For The Gauntlet Boss",
tags = {"gauntlet"},
type = PluginType.PVM,
enabledByDefault = false
name = "Gauntlet",
description = "All-in-one plugin for the Gauntlet.",
tags = {"Gauntlet"},
enabledByDefault = false,
type = PluginType.PVM
)
@Singleton
@Slf4j
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
public class GauntletPlugin extends Plugin
{
private static final Set<Integer> PLAYER_ANIMATIONS = ImmutableSet.of(426, 1167, 422, 423, 440, 428);
private static final Set<Integer> HUNLEFF_ANIMATIONS = ImmutableSet.of(AnimationID.HUNLEFF_ATTACK, AnimationID.HUNLEFF_TORNADO);
private static final Set<Integer> HUNLEFF_MAGE_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLEFF_MAGE_ATTACK, ProjectileID.HUNLEFF_CORRUPTED_MAGE_ATTACK);
private static final Set<Integer> HUNLEFF_RANGE_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLEFF_RANGE_ATTACK, ProjectileID.HUNLEFF_CORRUPTED_RANGE_ATTACK);
private static final int BOW_ATTACK = 426;
private static final int STAFF_ATTACK = 1167;
private static final int LIGHTNING_ANIMATION = 8418;
private static final Set<Integer> TORNADO_NPC_IDS = ImmutableSet.of(9025, 9039);
private static final Set<Integer> MELEE_ANIMATIONS = ImmutableSet.of(395, 401, 400, 401, 386, 390, 422, 423, 401, 428, 440);
private static final Set<Integer> PLAYER_ANIMATIONS = ImmutableSet.of(395, 401, 400, 401, 386, 390, 422, 423, 401, 428, 440, 426, 1167);
private static final Set<Integer> HUNLLEF_MAGE_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLLEF_MAGE_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_MAGE_ATTACK);
private static final Set<Integer> HUNLLEF_RANGE_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLLEF_RANGE_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_RANGE_ATTACK);
private static final Set<Integer> HUNLLEF_PRAYER_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLLEF_PRAYER_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_PRAYER_ATTACK);
private static final Set<Integer> HUNLLEF_PROJECTILES = ImmutableSet.of(ProjectileID.HUNLLEF_PRAYER_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_PRAYER_ATTACK,
ProjectileID.HUNLLEF_RANGE_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_RANGE_ATTACK, ProjectileID.HUNLLEF_MAGE_ATTACK, ProjectileID.HUNLLEF_CORRUPTED_MAGE_ATTACK
);
private static final Set<Integer> HUNLLEF_NPC_IDS = ImmutableSet.of(NpcID.CRYSTALLINE_HUNLLEF, NpcID.CRYSTALLINE_HUNLLEF_9022, NpcID.CRYSTALLINE_HUNLLEF_9023,
NpcID.CRYSTALLINE_HUNLLEF_9024, NpcID.CORRUPTED_HUNLLEF, NpcID.CORRUPTED_HUNLLEF_9036, NpcID.CORRUPTED_HUNLLEF_9037, NpcID.CORRUPTED_HUNLLEF_9038
);
private static final Set<Integer> RESOURCES = ImmutableSet.of(ObjectID.CRYSTAL_DEPOSIT, ObjectID.CORRUPT_DEPOSIT, ObjectID.PHREN_ROOTS,
ObjectID.PHREN_ROOTS_36066, ObjectID.FISHING_SPOT_36068, ObjectID.FISHING_SPOT_35971, ObjectID.GRYM_ROOT, ObjectID.GRYM_ROOT_36070,
ObjectID.LINUM_TIRINUM, ObjectID.LINUM_TIRINUM_36072
);
@Inject
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private Client client;
@Inject
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private EventBus eventBus;
private ClientThread clientThread;
@Inject
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private OverlayManager overlayManager;
@Inject
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private GauntletInfoBox GauntletInfoBox;
private GauntletOverlay overlay;
@Inject
@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
private GauntletCounter GauntletCounter;
private int attacks = 0;
private int playerAttacks = 0;
private Prayer nextPrayer;
private NPC hunllef;
private boolean firstHitDetected;
private HeadIcon currentPrayer;
private GauntletConfig config;
@Inject
@Getter(AccessLevel.NONE)
private EventBus eventBus;
@Inject
@Getter(AccessLevel.NONE)
private GauntletTimer timer;
@Inject
@Getter(AccessLevel.NONE)
private SkillIconManager skillIconManager;
@Setter(AccessLevel.PACKAGE)
private Hunllef hunllef;
private final Set<Resources> resources = new HashSet<>();
private final Set<Missiles> projectiles = new HashSet<>();
private final Map<String, Integer> items = new HashMap<>();
private Set<Tornado> tornadoes = new HashSet<>();
private boolean completeStartup = false;
private boolean countBossAttacks;
private boolean countPlayerAttacks;
private boolean displayTimerChat;
private boolean highlightResources;
private boolean highlightResourcesIcons;
private boolean highlightWidget;
private boolean overlayBoss;
private boolean overlayBossPrayer;
private boolean overlayTornadoes;
@Setter(AccessLevel.PACKAGE)
private boolean flash;
private boolean flashOnWrongAttack;
private Color highlightResourcesColor;
private boolean displayTimerWidget;
private boolean timerVisible = true;
private boolean uniqueAttackVisual;
private boolean uniquePrayerAudio;
private boolean uniquePrayerVisual;
private int resourceIconSize;
private int projectileIconSize;
@Override
protected void startUp() throws Exception
@Provides
GauntletConfig getConfig(ConfigManager configManager)
{
addSubscriptions();
overlayManager.add(GauntletInfoBox);
overlayManager.add(GauntletCounter);
reset();
return configManager.getConfig(GauntletConfig.class);
}
@Override
protected void shutDown() throws Exception
protected void startUp()
{
addSubscriptions();
updateConfig();
timerVisible = this.displayTimerWidget;
timer.resetStates();
if (timerVisible)
{
overlayManager.add(timer);
}
overlayManager.add(overlay);
if (client.getGameState() != GameState.STARTING && client.getGameState() != GameState.UNKNOWN)
{
completeStartup = false;
clientThread.invoke(() -> {
timer.initStates();
completeStartup = true;
});
}
else
{
completeStartup = true;
}
}
@Override
protected void shutDown()
{
eventBus.unregister(this);
overlayManager.remove(GauntletInfoBox);
overlayManager.remove(GauntletCounter);
reset();
timer.resetStates();
if (timerVisible)
{
overlayManager.remove(timer);
timerVisible = false;
}
overlayManager.remove(overlay);
resources.clear();
projectiles.clear();
tornadoes.clear();
setHunllef(null);
}
private void addSubscriptions()
{
eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged);
eventBus.subscribe(NpcSpawned.class, this, this::onNpcSpawned);
eventBus.subscribe(NpcDespawned.class, this, this::onNpcDespawned);
eventBus.subscribe(ProjectileSpawned.class, this, this::onProjectileSpawned);
eventBus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventBus.subscribe(GameObjectDespawned.class, this, this::onGameObjectDespawned);
eventBus.subscribe(GameObjectSpawned.class, this, this::onGameObjectSpawned);
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(NpcDespawned.class, this, this::onNpcDespawned);
eventBus.subscribe(NpcSpawned.class, this, this::onNpcSpawned);
eventBus.subscribe(ProjectileSpawned.class, this, this::onProjectileSpawned);
eventBus.subscribe(VarbitChanged.class, this, this::onVarbitChanged);
}
private void onAnimationChanged(AnimationChanged event)
{
if (getHunllef() == null || !isInRoom())
final Actor actor = event.getActor();
// This section handles the player counter.
if (actor instanceof Player && fightingBoss())
{
final Player player = (Player) actor;
final int anim = player.getAnimation();
if (!player.getName().equals(client.getLocalPlayer().getName()) || anim == -1 || !PLAYER_ANIMATIONS.contains(anim))
{
return;
}
NPCDefinition comp = hunllef.getNpc().getDefinition();
if (comp == null || comp.getOverheadIcon() == null)
{
return;
}
final HeadIcon prayer = comp.getOverheadIcon();
switch (prayer)
{
case MELEE:
if (MELEE_ANIMATIONS.contains(anim))
{
setFlash(true);
return;
}
hunllef.updatePlayerAttack();
break;
case RANGED:
if (BOW_ATTACK == anim)
{
setFlash(true);
return;
}
hunllef.updatePlayerAttack();
break;
case MAGIC:
if (STAFF_ATTACK == anim)
{
setFlash(true);
return;
}
hunllef.updatePlayerAttack();
break;
}
}
// This section handles the boss attack counter if they perform a lightning attack.
if (actor instanceof NPC)
{
final NPC npc = (NPC) actor;
if (npc.getAnimation() == LIGHTNING_ANIMATION)
{
hunllef.updateAttack(LIGHTNING);
}
}
}
private void onConfigChanged(ConfigChanged event)
{
if (!event.getGroup().equals("Gauntlet"))
{
return;
}
final int anim = event.getActor().getAnimation();
updateConfig();
if (HUNLEFF_ANIMATIONS.contains(anim))
if (event.getKey().equals("displayTimerWidget"))
{
setAttacks(getAttacks() + 1);
if (getAttacks() == 4)
if (this.displayTimerWidget && !timerVisible)
{
if (getNextPrayer() == Prayer.PROTECT_FROM_MISSILES)
{
log.debug("Attacks are: {}, switching to prot mage", getAttacks());
setNextPrayer(Prayer.PROTECT_FROM_MAGIC);
}
else if (getNextPrayer() == Prayer.PROTECT_FROM_MAGIC)
{
log.debug("Attacks are: {}, switching to prot missiles", getAttacks());
setNextPrayer(Prayer.PROTECT_FROM_MISSILES);
}
setAttacks(0);
overlayManager.add(timer);
timerVisible = true;
}
else if (!this.displayTimerWidget && timerVisible)
{
overlayManager.remove(timer);
timerVisible = false;
}
}
else if (PLAYER_ANIMATIONS.contains(anim))
}
private void onGameObjectDespawned(GameObjectDespawned event)
{
final GameObject obj = event.getGameObject();
if (RESOURCES.contains(obj.getId()))
{
setPlayerAttacks(getPlayerAttacks() - 1);
if (getPlayerAttacks() == 0)
{
setPlayerAttacks(6);
}
resources.removeIf(object -> object.getGameObject() == obj);
}
}
private void onGameObjectSpawned(GameObjectSpawned event)
{
final GameObject obj = event.getGameObject();
if (RESOURCES.contains(obj.getId()))
{
resources.add(new Resources(obj, event.getTile(), skillIconManager));
}
}
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOADING)
{
resources.clear();
}
}
private void onGameTick(GameTick event)
{
if (getHunllef() == null || !isInRoom())
// This handles the timer based on player health.
if (this.completeStartup)
{
return;
timer.checkStates(false);
}
HeadIcon overhead = getOverheadIcon(getHunllef());
if (overhead == null)
if (!tornadoes.isEmpty())
{
return;
tornadoes.forEach(Tornado::updateTimeLeft);
}
switch (overhead)
if (hunllef != null)
{
case MELEE:
case MAGIC:
case RANGED:
if (currentPrayer == overhead)
{
return;
}
currentPrayer = overhead;
setPlayerAttacks(6);
break;
if (hunllef.getTicksUntilAttack() > 0)
{
hunllef.setTicksUntilAttack(hunllef.getTicksUntilAttack() - 1);
}
}
}
private void onNpcDespawned(NpcDespawned event)
{
final NPC npc = event.getNpc();
if (npc.getName() == null || !npc.getName().toLowerCase().contains("hunllef"))
if (HUNLLEF_NPC_IDS.contains(npc.getId()))
{
return;
setHunllef(null);
}
else if (TORNADO_NPC_IDS.contains(npc.getId()))
{
tornadoes.removeIf(tornado -> tornado.getNpc() == npc);
}
reset();
}
private void onNpcSpawned(NpcSpawned event)
{
final NPC npc = event.getNpc();
if (npc.getName() == null || !npc.getName().toLowerCase().contains("hunllef"))
if (HUNLLEF_NPC_IDS.contains(npc.getId()))
{
return;
setHunllef(new Hunllef(npc, skillIconManager));
}
else if (TORNADO_NPC_IDS.contains(npc.getId()))
{
tornadoes.add(new Tornado(npc));
}
setPlayerAttacks(6);
setAttacks(0);
setHunllef(npc);
}
private void onProjectileSpawned(ProjectileSpawned event)
{
if (getHunllef() == null || !isInRoom() || isFirstHitDetected())
if (hunllef == null)
{
return;
}
final int projectileID = event.getProjectile().getId();
final Projectile proj = event.getProjectile();
if (HUNLEFF_MAGE_PROJECTILES.contains(projectileID))
if (HUNLLEF_PROJECTILES.contains(proj.getId()))
{
setNextPrayer(Prayer.PROTECT_FROM_MAGIC);
setFirstHitDetected(true);
}
else if (HUNLEFF_RANGE_PROJECTILES.contains(projectileID))
{
setNextPrayer(Prayer.PROTECT_FROM_MISSILES);
setFirstHitDetected(true);
projectiles.add(new Missiles(proj, skillIconManager));
if (HUNLLEF_MAGE_PROJECTILES.contains(proj.getId()))
{
hunllef.updateAttack(MAGIC);
}
else if (HUNLLEF_PRAYER_PROJECTILES.contains(proj.getId()))
{
hunllef.updateAttack(PRAYER);
if (this.uniquePrayerAudio)
{
client.playSoundEffect(SoundEffectID.MAGIC_SPLASH_BOING);
}
}
else if (HUNLLEF_RANGE_PROJECTILES.contains(proj.getId()))
{
hunllef.updateAttack(RANGE);
}
}
}
private void reset()
private void onVarbitChanged(VarbitChanged event)
{
setHunllef(null);
setNextPrayer(null);
setCurrentPrayer(null);
setFirstHitDetected(false);
setAttacks(0);
setPlayerAttacks(6);
}
private HeadIcon getOverheadIcon(NPC npc)
{
NPCDefinition composition = npc.getDefinition();
if (composition != null)
if (this.completeStartup)
{
return composition.getOverheadIcon();
timer.checkStates(true);
}
return null;
}
boolean isInRoom()
boolean fightingBoss()
{
return client.getVar(Varbits.GAUNTLET_FINAL_ROOM_ENTERED) == 1;
}
boolean startedGauntlet()
{
return client.getVar(Varbits.GAUNTLET_ENTERED) == 1;
}
private void updateConfig()
{
this.highlightResources = config.highlightResources();
this.highlightResourcesColor = config.highlightResourcesColor();
this.highlightResourcesIcons = config.highlightResourcesIcons();
this.flashOnWrongAttack = config.flashOnWrongAttack();
this.highlightWidget = config.highlightWidget();
this.resourceIconSize = config.resourceIconSize();
this.projectileIconSize = config.projectileIconSize();
this.countBossAttacks = config.countBossAttacks();
this.countPlayerAttacks = config.countPlayerAttacks();
this.uniquePrayerAudio = config.uniquePrayerAudio();
this.uniquePrayerVisual = config.uniquePrayerVisual();
this.uniqueAttackVisual = config.uniqueAttackVisual();
this.overlayBoss = config.overlayBoss();
this.overlayBossPrayer = config.overlayBossPrayer();
this.overlayTornadoes = config.overlayTornadoes();
this.displayTimerWidget = config.displayTimerWidget();
this.displayTimerChat = config.displayTimerChat();
}
}

View File

@@ -0,0 +1,313 @@
/*
* Copyright (c) 2018, Seth <http://github.com/sethtroll>
* 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.gauntlet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import javax.inject.Inject;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG;
import net.runelite.api.Player;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.chat.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import static net.runelite.client.plugins.gauntlet.GauntletTimer.RaidState.IN_BOSS;
import static net.runelite.client.plugins.gauntlet.GauntletTimer.RaidState.IN_RAID;
import static net.runelite.client.plugins.gauntlet.GauntletTimer.RaidState.UNKNOWN;
import net.runelite.client.ui.overlay.Overlay;
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.TitleComponent;
import net.runelite.client.ui.overlay.components.table.TableAlignment;
import net.runelite.client.ui.overlay.components.table.TableComponent;
class GauntletTimer extends Overlay
{
private final Client client;
private final GauntletPlugin plugin;
private final PanelComponent panelComponent = new PanelComponent();
@Inject
private ChatMessageManager chatMessageManager;
private long timeRaidStart = -1L;
private long timeBossEnter = -1L;
private RaidState currentState = UNKNOWN;
@Inject
public GauntletTimer(Client client, GauntletPlugin plugin)
{
super(plugin);
setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT);
setPriority(OverlayPriority.HIGH);
this.client = client;
this.plugin = plugin;
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Gauntlet Timer Overlay"));
}
/**
* Resets the timer.
*/
void resetStates()
{
timeRaidStart = -1L;
timeBossEnter = -1L;
currentState = UNKNOWN;
}
/**
* This is called when the player resets the plugin mid-raid. We do not want to confuse the timer.
* <p>
* TODO: Originally, this function will disable the timer if the plugin is started mid raid.
* Unfortunately, VARBITS can't be checked unless you're on the client thread.
* I've no idea how to access RL's task handler.
* Good luck to you. If you restart plugin mid raid, oh well. Your timer's going to be inaccurate.
*/
void initStates()
{
timeRaidStart = -1L;
timeBossEnter = -1L;
if (plugin.startedGauntlet())
{
currentState = IN_RAID;
if (plugin.fightingBoss())
{
currentState = IN_BOSS;
}
}
else
{
currentState = UNKNOWN;
}
}
/**
* Converts the different between two epoch times into minutes:seconds format.
*
* @param epochA long
* @param epochB long
* @return String
*/
private String calculateElapsedTime(long epochA, long epochB)
{
long max = Math.max(epochA, epochB);
long min = Math.min(epochA, epochB);
long elapsedEpoch = max - min;
long seconds = elapsedEpoch / 1000L;
long minutes = seconds / 60L;
seconds = seconds % 60;
if (seconds == 0)
{
return minutes + ":00";
}
if (seconds < 10)
{
return minutes + ":0" + seconds;
}
return minutes + ":" + seconds;
}
/**
* Called when varbit changes. See if the the raid state has changed.
*/
void checkStates(boolean checkVarps)
{
final Player p = client.getLocalPlayer();
if (p == null || !plugin.isCompleteStartup())
{
return;
}
if (checkVarps)
{
switch (currentState)
{
case UNKNOWN:
if (plugin.startedGauntlet() && p.getHealthRatio() != 0)
{
// Player has started a new raid.
if (!plugin.fightingBoss())
{
currentState = IN_RAID;
timeRaidStart = System.currentTimeMillis();
return;
}
currentState = IN_RAID;
timeRaidStart = timeBossEnter = System.currentTimeMillis();
}
break;
case IN_RAID:
if (!plugin.startedGauntlet())
{
printPrepTime();
resetStates();
return;
}
if (plugin.fightingBoss())
{
// Player has begun the boss fight.
printPrepTime();
currentState = IN_BOSS;
timeBossEnter = System.currentTimeMillis();
}
break;
case IN_BOSS:
if (!plugin.fightingBoss() || !plugin.startedGauntlet())
{
// Player has killed the boss.
resetStates();
}
break;
}
}
else
{
if (currentState == IN_BOSS && p.getHealthRatio() == 0)
{
printBossTime();
resetStates();
}
}
}
private void printPrepTime()
{
if (!plugin.isDisplayTimerChat() || timeRaidStart == -1L)
{
return;
}
String elapsedTime = calculateElapsedTime(System.currentTimeMillis(), timeRaidStart);
final ChatMessageBuilder prepmessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Preparation time: ")
.append(ChatColorType.HIGHLIGHT)
.append(elapsedTime);
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(prepmessage.build())
.build());
}
private void printBossTime()
{
if (!plugin.isDisplayTimerChat() || timeRaidStart == -1L || timeBossEnter == -1L)
{
return;
}
String elapsedBossTime = calculateElapsedTime(System.currentTimeMillis(), timeBossEnter);
String elapsedPrepTime = calculateElapsedTime(timeRaidStart, timeBossEnter);
String elapsedTotalTime = calculateElapsedTime(System.currentTimeMillis(), timeRaidStart);
final ChatMessageBuilder challengedurationmessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Challenge duration: ")
.append(ChatColorType.HIGHLIGHT)
.append(elapsedTotalTime);
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(challengedurationmessage.build())
.build());
final ChatMessageBuilder prepdeathmessage = new ChatMessageBuilder()
.append(ChatColorType.NORMAL)
.append("Preparation time: ")
.append(ChatColorType.HIGHLIGHT)
.append(elapsedPrepTime)
.append(ChatColorType.NORMAL)
.append(" player/boss death time: ")
.append(ChatColorType.HIGHLIGHT)
.append(elapsedBossTime);
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
.runeLiteFormattedMessage(prepdeathmessage.build())
.build());
}
@Override
public Dimension render(Graphics2D graphics)
{
if (currentState == UNKNOWN)
{
return null;
}
panelComponent.getChildren().clear();
panelComponent.getChildren().add(TitleComponent.builder().text("Gauntlet Timer").color(Color.WHITE).build());
TableComponent tableComponent = new TableComponent();
tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT);
if (timeRaidStart == -1L)
{ // User restarted the plugin mid raid. Timer is inaccurate.
tableComponent.addRow("Inactive", "0:00");
}
else
{
String elapsedPrepTime, elapsedBossTime, elapsedTotalTime;
elapsedTotalTime = calculateElapsedTime(System.currentTimeMillis(), timeRaidStart);
if (currentState == IN_RAID)
{
elapsedPrepTime = calculateElapsedTime(timeRaidStart, System.currentTimeMillis());
elapsedBossTime = "0:00";
}
else
{
elapsedPrepTime = calculateElapsedTime(timeRaidStart, timeBossEnter);
elapsedBossTime = calculateElapsedTime(System.currentTimeMillis(), timeBossEnter);
}
tableComponent.addRow("Preparation", elapsedPrepTime);
tableComponent.addRow("Boss Fight", elapsedBossTime);
tableComponent.addRow("Total Time", elapsedTotalTime);
panelComponent.getChildren().add(tableComponent);
}
return panelComponent.render(graphics);
}
public enum RaidState
{
UNKNOWN, IN_RAID, IN_BOSS
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.Color;
import java.awt.image.BufferedImage;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.NPC;
import net.runelite.api.Prayer;
import net.runelite.api.Skill;
import net.runelite.client.game.SkillIconManager;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
public class Hunllef
{
private NPC npc;
private int bossAttacks;
private int playerAttacks;
private int ticksUntilAttack;
private BufferedImage mage;
private BufferedImage range;
private BossAttackPhase currentPhase;
Hunllef(NPC npc, SkillIconManager skillIconManager)
{
this.npc = npc;
this.bossAttacks = 0;
this.playerAttacks = 6;
this.ticksUntilAttack = 0;
this.mage = skillIconManager.getSkillImage(Skill.MAGIC);
this.range = skillIconManager.getSkillImage(Skill.RANGED);
this.currentPhase = BossAttackPhase.UNKNOWN;
}
void updatePlayerAttack()
{
playerAttacks--;
if (playerAttacks <= 0)
{
playerAttacks = 6;
}
}
void updateAttack(BossAttack style)
{
ticksUntilAttack = 6;
if (style == BossAttack.PRAYER)
{
style = BossAttack.MAGIC;
}
if (style == BossAttack.LIGHTNING)
{
bossAttacks--;
}
else if (style == BossAttack.RANGE)
{
if (currentPhase != BossAttackPhase.RANGE)
{
currentPhase = BossAttackPhase.RANGE;
bossAttacks = 3;
}
else
{
bossAttacks--;
}
}
else if (style == BossAttack.MAGIC)
{
if (currentPhase != BossAttackPhase.MAGIC)
{
currentPhase = BossAttackPhase.MAGIC;
bossAttacks = 3;
}
else
{
bossAttacks--;
}
}
if (bossAttacks <= 0)
{
BossAttackPhase nextPhase;
switch (currentPhase)
{
case MAGIC:
bossAttacks = 4;
nextPhase = BossAttackPhase.RANGE;
break;
case RANGE:
bossAttacks = 4;
nextPhase = BossAttackPhase.MAGIC;
break;
default:
bossAttacks = 0;
nextPhase = BossAttackPhase.UNKNOWN;
break;
}
currentPhase = nextPhase;
}
}
@AllArgsConstructor
@Getter(AccessLevel.PACKAGE)
enum BossAttackPhase
{
MAGIC(Color.CYAN, Prayer.PROTECT_FROM_MAGIC),
RANGE(Color.GREEN, Prayer.PROTECT_FROM_MISSILES),
UNKNOWN(Color.WHITE, null);
private Color color;
private Prayer prayer;
}
enum BossAttack
{
MAGIC,
RANGE,
PRAYER,
LIGHTNING
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.Color;
import java.awt.image.BufferedImage;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.Projectile;
import net.runelite.api.ProjectileID;
import net.runelite.api.Skill;
import net.runelite.client.game.SkillIconManager;
@Getter(AccessLevel.PACKAGE)
class Missiles
{
private Projectile projectile;
private int id;
private BufferedImage image;
private Color color;
Missiles(Projectile projectile, SkillIconManager skillIconManager)
{
this.projectile = projectile;
this.id = projectile.getId();
this.image = assignedImage(skillIconManager, id);
this.color = assignedColor(id);
}
private Color assignedColor(int id)
{
switch (id)
{
case ProjectileID.HUNLLEF_MAGE_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_MAGE_ATTACK:
return Color.CYAN;
case ProjectileID.HUNLLEF_RANGE_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_RANGE_ATTACK:
return Color.GREEN;
case ProjectileID.HUNLLEF_PRAYER_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_PRAYER_ATTACK:
return Color.MAGENTA;
default:
return null;
}
}
private BufferedImage assignedImage(SkillIconManager SkillIconManager, int id)
{
switch (id)
{
case ProjectileID.HUNLLEF_MAGE_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_MAGE_ATTACK:
return SkillIconManager.getSkillImage(Skill.MAGIC);
case ProjectileID.HUNLLEF_RANGE_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_RANGE_ATTACK:
return SkillIconManager.getSkillImage(Skill.RANGED);
case ProjectileID.HUNLLEF_PRAYER_ATTACK:
case ProjectileID.HUNLLEF_CORRUPTED_PRAYER_ATTACK:
return SkillIconManager.getSkillImage(Skill.PRAYER);
default:
return null;
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* 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.gauntlet;
import java.awt.image.BufferedImage;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.GameObject;
import net.runelite.api.ObjectID;
import net.runelite.api.Skill;
import net.runelite.api.Tile;
import net.runelite.client.game.SkillIconManager;
@Getter(AccessLevel.PACKAGE)
class Resources
{
private GameObject gameObject;
private Tile tile;
private BufferedImage image;
Resources(GameObject object, Tile tile, SkillIconManager skillIconManager)
{
this.gameObject = object;
this.tile = tile;
this.image = assignedImage(skillIconManager, object.getId());
}
private BufferedImage assignedImage(SkillIconManager SkillIconManager, int id)
{
switch (id)
{
case ObjectID.CRYSTAL_DEPOSIT:
case ObjectID.CORRUPT_DEPOSIT:
return SkillIconManager.getSkillImage(Skill.MINING);
case ObjectID.PHREN_ROOTS:
case ObjectID.PHREN_ROOTS_36066:
return SkillIconManager.getSkillImage(Skill.WOODCUTTING);
case ObjectID.FISHING_SPOT_36068:
case ObjectID.FISHING_SPOT_35971:
return SkillIconManager.getSkillImage(Skill.FISHING);
case ObjectID.GRYM_ROOT:
case ObjectID.GRYM_ROOT_36070:
return SkillIconManager.getSkillImage(Skill.HERBLORE);
case ObjectID.LINUM_TIRINUM:
case ObjectID.LINUM_TIRINUM_36072:
return SkillIconManager.getSkillImage(Skill.FARMING);
default:
return null;
}
}
}

View File

@@ -1,5 +1,4 @@
/*
* Copyright (c) 2019, xperiaclash <https://github.com/xperiaclash>
* Copyright (c) 2019, ganom <https://github.com/Ganom>
* All rights reserved.
*
@@ -22,21 +21,30 @@
* (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.gauntlet;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigItem;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.NPC;
public interface GauntletPluginConfig extends Config
@Getter(AccessLevel.PACKAGE)
class Tornado
{
@ConfigItem(
position = 0,
keyName = "gauntletEnable",
name = "Enable gauntlet",
description = "gauntlet boss prayer"
)
default boolean enableGauntlet()
private NPC npc;
private int timeLeft;
Tornado(NPC npc)
{
return true;
this.npc = npc;
this.timeLeft = 20;
}
}
void updateTimeLeft()
{
if (timeLeft > 0)
{
timeLeft--;
}
}
}

View File

@@ -45,6 +45,7 @@ import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Prayer;
import net.runelite.api.TileObject;
import net.runelite.api.VarClientInt;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldArea;
import net.runelite.api.coords.WorldPoint;
@@ -348,7 +349,7 @@ public class OverlayUtil
{
Widget widget = client.getWidget(prayer.getWidgetInfo());
if (widget == null || widget.isHidden())
if (widget == null || client.getVar(VarClientInt.PLAYER_INTERFACE_CONTAINER_OPENED) != 5)
{
return null;
}