Overhaul of the Tick Timers plugin. (#757)

* Overhaul of the Tick Timers plugin.
Added new OverlayUtils that are commonly found.
Added Attack Speed to npcManager. (Thanks wiki <3)
Updated Prayer API to contain widget info as well.

* Remove unnecessary code.

* Add Dag King animations.

* Update NPCManager to use int instead of Integer.

* Add Waterbith Region check for DKs

* Make valid region check happen only during game state change event.

* Renaming and other misc.

* Renaming and other misc.
This commit is contained in:
Ganom
2019-06-26 23:08:21 -04:00
committed by James
parent 24a6357baf
commit 7a7db495d4
14 changed files with 3433 additions and 459 deletions

View File

@@ -278,4 +278,31 @@ public final class AnimationID
public static final int GENERAL_AUTO1 = 7018; public static final int GENERAL_AUTO1 = 7018;
public static final int GENERAL_AUTO2 = 7020; public static final int GENERAL_AUTO2 = 7020;
public static final int GENERAL_AUTO3 = 7021; public static final int GENERAL_AUTO3 = 7021;
//Zammy-poo
public static final int ZAMMY_GENERIC_AUTO = 64;
public static final int KRIL_AUTO = 6948;
public static final int KRIL_SPEC = 6950;
public static final int ZAKL_AUTO = 7077;
public static final int BALFRUG_AUTO = 4630;
//Sara-Poo
public static final int ZILYANA_MELEE_AUTO = 6964;
public static final int ZILYANA_AUTO = 6967;
public static final int ZILYANA_SPEC = 6970;
public static final int STARLIGHT_AUTO = 6376;
public static final int BREE_AUTO = 7026;
public static final int GROWLER_AUTO = 7037;
//Arma-Poo
public static final int KREE_RANGED = 6978;
public static final int SKREE_AUTO = 6955;
public static final int GEERIN_AUTO = 6956;
public static final int GEERIN_FLINCH = 6958;
public static final int KILISA_AUTO = 6957;
//Dag Kings
public static final int DAG_REX = 2853;
public static final int DAG_PRIME = 2854;
public static final int DAG_SUPREME = 2855;
} }

View File

@@ -24,155 +24,147 @@
*/ */
package net.runelite.api; package net.runelite.api;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.widgets.WidgetInfo;
/** /**
* An enumeration of different prayer spells. * An enumeration of different prayer spells.
*/ */
@Getter
@AllArgsConstructor
public enum Prayer public enum Prayer
{ {
/** /**
* Thick Skin (Level 1, Defence). * Thick Skin (Level 1, Defence).
*/ */
THICK_SKIN(Varbits.PRAYER_THICK_SKIN, 5.0), THICK_SKIN(Varbits.PRAYER_THICK_SKIN, 5.0, WidgetInfo.PRAYER_THICK_SKIN),
/** /**
* Burst of Strength (Level 4, Strength). * Burst of Strength (Level 4, Strength).
*/ */
BURST_OF_STRENGTH(Varbits.PRAYER_BURST_OF_STRENGTH, 5.0), BURST_OF_STRENGTH(Varbits.PRAYER_BURST_OF_STRENGTH, 5.0, WidgetInfo.PRAYER_BURST_OF_STRENGTH),
/** /**
* Clarity of Thought (Level 7, Attack). * Clarity of Thought (Level 7, Attack).
*/ */
CLARITY_OF_THOUGHT(Varbits.PRAYER_CLARITY_OF_THOUGHT, 5.0), CLARITY_OF_THOUGHT(Varbits.PRAYER_CLARITY_OF_THOUGHT, 5.0, WidgetInfo.PRAYER_CLARITY_OF_THOUGHT),
/** /**
* Sharp Eye (Level 8, Ranging). * Sharp Eye (Level 8, Ranging).
*/ */
SHARP_EYE(Varbits.PRAYER_SHARP_EYE, 5.0), SHARP_EYE(Varbits.PRAYER_SHARP_EYE, 5.0, WidgetInfo.PRAYER_SHARP_EYE),
/** /**
* Mystic Will (Level 9, Magic). * Mystic Will (Level 9, Magic).
*/ */
MYSTIC_WILL(Varbits.PRAYER_MYSTIC_WILL, 5.0), MYSTIC_WILL(Varbits.PRAYER_MYSTIC_WILL, 5.0, WidgetInfo.PRAYER_MYSTIC_WILL),
/** /**
* Rock Skin (Level 10, Defence). * Rock Skin (Level 10, Defence).
*/ */
ROCK_SKIN(Varbits.PRAYER_ROCK_SKIN, 10.0), ROCK_SKIN(Varbits.PRAYER_ROCK_SKIN, 10.0, WidgetInfo.PRAYER_ROCK_SKIN),
/** /**
* Superhuman Strength (Level 13, Strength). * Superhuman Strength (Level 13, Strength).
*/ */
SUPERHUMAN_STRENGTH(Varbits.PRAYER_SUPERHUMAN_STRENGTH, 10.0), SUPERHUMAN_STRENGTH(Varbits.PRAYER_SUPERHUMAN_STRENGTH, 10.0, WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH),
/** /**
* Improved Reflexes (Level 16, Attack). * Improved Reflexes (Level 16, Attack).
*/ */
IMPROVED_REFLEXES(Varbits.PRAYER_IMPROVED_REFLEXES, 10.0), IMPROVED_REFLEXES(Varbits.PRAYER_IMPROVED_REFLEXES, 10.0, WidgetInfo.PRAYER_IMPROVED_REFLEXES),
/** /**
* Rapid Restore (Level 19, Stats). * Rapid Restore (Level 19, Stats).
*/ */
RAPID_RESTORE(Varbits.PRAYER_RAPID_RESTORE, 60.0 / 36.0), RAPID_RESTORE(Varbits.PRAYER_RAPID_RESTORE, 60.0 / 36.0, WidgetInfo.PRAYER_RAPID_RESTORE),
/** /**
* Rapid Heal (Level 22, Hitpoints). * Rapid Heal (Level 22, Hitpoints).
*/ */
RAPID_HEAL(Varbits.PRAYER_RAPID_HEAL, 60.0 / 18), RAPID_HEAL(Varbits.PRAYER_RAPID_HEAL, 60.0 / 18, WidgetInfo.PRAYER_RAPID_HEAL),
/** /**
* Protect Item (Level 25). * Protect Item (Level 25).
*/ */
PROTECT_ITEM(Varbits.PRAYER_PROTECT_ITEM, 60.0 / 18), PROTECT_ITEM(Varbits.PRAYER_PROTECT_ITEM, 60.0 / 18, WidgetInfo.PRAYER_PROTECT_ITEM),
/** /**
* Hawk Eye (Level 26, Ranging). * Hawk Eye (Level 26, Ranging).
*/ */
HAWK_EYE(Varbits.PRAYER_HAWK_EYE, 10.0), HAWK_EYE(Varbits.PRAYER_HAWK_EYE, 10.0, WidgetInfo.PRAYER_HAWK_EYE),
/** /**
* Mystic Lore (Level 27, Magic). * Mystic Lore (Level 27, Magic).
*/ */
MYSTIC_LORE(Varbits.PRAYER_MYSTIC_LORE, 10.0), MYSTIC_LORE(Varbits.PRAYER_MYSTIC_LORE, 10.0, WidgetInfo.PRAYER_MYSTIC_LORE),
/** /**
* Steel Skin (Level 28, Defence). * Steel Skin (Level 28, Defence).
*/ */
STEEL_SKIN(Varbits.PRAYER_STEEL_SKIN, 20.0), STEEL_SKIN(Varbits.PRAYER_STEEL_SKIN, 20.0, WidgetInfo.PRAYER_STEEL_SKIN),
/** /**
* Ultimate Strength (Level 31, Strength). * Ultimate Strength (Level 31, Strength).
*/ */
ULTIMATE_STRENGTH(Varbits.PRAYER_ULTIMATE_STRENGTH, 20.0), ULTIMATE_STRENGTH(Varbits.PRAYER_ULTIMATE_STRENGTH, 20.0, WidgetInfo.PRAYER_ULTIMATE_STRENGTH),
/** /**
* Incredible Reflexes (Level 34, Attack). * Incredible Reflexes (Level 34, Attack).
*/ */
INCREDIBLE_REFLEXES(Varbits.PRAYER_INCREDIBLE_REFLEXES, 20.0), INCREDIBLE_REFLEXES(Varbits.PRAYER_INCREDIBLE_REFLEXES, 20.0, WidgetInfo.PRAYER_INCREDIBLE_REFLEXES),
/** /**
* Protect from Magic (Level 37). * Protect from Magic (Level 37).
*/ */
PROTECT_FROM_MAGIC(Varbits.PRAYER_PROTECT_FROM_MAGIC, 20.0), PROTECT_FROM_MAGIC(Varbits.PRAYER_PROTECT_FROM_MAGIC, 20.0, WidgetInfo.PRAYER_PROTECT_FROM_MAGIC),
/** /**
* Protect from Missiles (Level 40). * Protect from Missiles (Level 40).
*/ */
PROTECT_FROM_MISSILES(Varbits.PRAYER_PROTECT_FROM_MISSILES, 20.0), PROTECT_FROM_MISSILES(Varbits.PRAYER_PROTECT_FROM_MISSILES, 20.0, WidgetInfo.PRAYER_PROTECT_FROM_MISSILES),
/** /**
* Protect from Melee (Level 43). * Protect from Melee (Level 43).
*/ */
PROTECT_FROM_MELEE(Varbits.PRAYER_PROTECT_FROM_MELEE, 20.0), PROTECT_FROM_MELEE(Varbits.PRAYER_PROTECT_FROM_MELEE, 20.0, WidgetInfo.PRAYER_PROTECT_FROM_MELEE),
/** /**
* Eagle Eye (Level 44, Ranging). * Eagle Eye (Level 44, Ranging).
*/ */
EAGLE_EYE(Varbits.PRAYER_EAGLE_EYE, 20.0), EAGLE_EYE(Varbits.PRAYER_EAGLE_EYE, 20.0, WidgetInfo.PRAYER_EAGLE_EYE),
/** /**
* Mystic Might (Level 45, Magic). * Mystic Might (Level 45, Magic).
*/ */
MYSTIC_MIGHT(Varbits.PRAYER_MYSTIC_MIGHT, 20.0), MYSTIC_MIGHT(Varbits.PRAYER_MYSTIC_MIGHT, 20.0, WidgetInfo.PRAYER_MYSTIC_MIGHT),
/** /**
* Retribution (Level 46). * Retribution (Level 46).
*/ */
RETRIBUTION(Varbits.PRAYER_RETRIBUTION, 5.0), RETRIBUTION(Varbits.PRAYER_RETRIBUTION, 5.0, WidgetInfo.PRAYER_RETRIBUTION),
/** /**
* Redemption (Level 49). * Redemption (Level 49).
*/ */
REDEMPTION(Varbits.PRAYER_REDEMPTION, 10.0), REDEMPTION(Varbits.PRAYER_REDEMPTION, 10.0, WidgetInfo.PRAYER_REDEMPTION),
/** /**
* Smite (Level 52). * Smite (Level 52).
*/ */
SMITE(Varbits.PRAYER_SMITE, 30.0), SMITE(Varbits.PRAYER_SMITE, 30.0, WidgetInfo.PRAYER_SMITE),
/** /**
* Chivalry (Level 60, Defence/Strength/Attack). * Chivalry (Level 60, Defence/Strength/Attack).
*/ */
CHIVALRY(Varbits.PRAYER_CHIVALRY, 40.0), CHIVALRY(Varbits.PRAYER_CHIVALRY, 40.0, WidgetInfo.PRAYER_CHIVALRY),
/** /**
* Piety (Level 70, Defence/Strength/Attack). * Piety (Level 70, Defence/Strength/Attack).
*/ */
PIETY(Varbits.PRAYER_PIETY, 40.0), PIETY(Varbits.PRAYER_PIETY, 40.0, WidgetInfo.PRAYER_PIETY),
/** /**
* Preserve (Level 55). * Preserve (Level 55).
*/ */
PRESERVE(Varbits.PRAYER_PRESERVE, 60.0 / 18), PRESERVE(Varbits.PRAYER_PRESERVE, 60.0 / 18, WidgetInfo.PRAYER_PRESERVE),
/** /**
* Rigour (Level 74, Ranging/Damage/Defence). * Rigour (Level 74, Ranging/Damage/Defence).
*/ */
RIGOUR(Varbits.PRAYER_RIGOUR, 40.0), RIGOUR(Varbits.PRAYER_RIGOUR, 40.0, WidgetInfo.PRAYER_RIGOUR),
/** /**
* Augury (Level 77, Magic/Magic Def./Defence). * Augury (Level 77, Magic/Magic Def./Defence).
*/ */
AUGURY(Varbits.PRAYER_AUGURY, 40.0); AUGURY(Varbits.PRAYER_AUGURY, 40.0, WidgetInfo.PRAYER_AUGURY);
private final Varbits varbit;
private final double drainRate;
Prayer(Varbits varbit, double drainRate)
{
this.varbit = varbit;
this.drainRate = drainRate;
}
/** /**
* Gets the varbit that stores whether the prayer is active or not. * Gets the varbit that stores whether the prayer is active or not.
*
* @return the prayer active varbit
*/ */
public Varbits getVarbit() private final Varbits varbit;
{
return varbit;
}
/** /**
* Gets the prayer drain rate (measured in pray points/minute) * Gets the prayer drain rate (measured in pray points/minute)
*
* @return the prayer drain rate
*/ */
public double getDrainRate() private final double drainRate;
{
return drainRate; /**
} * Gets the widget info for prayer
*/
private final WidgetInfo widgetInfo;
} }

View File

@@ -59,6 +59,7 @@ public class NPCManager
/** /**
* Returns the {@link NPCStats} for target NPC id * Returns the {@link NPCStats} for target NPC id
*
* @param npcId NPC id * @param npcId NPC id
* @return the {@link NPCStats} or null if unknown * @return the {@link NPCStats} or null if unknown
*/ */
@@ -70,23 +71,41 @@ public class NPCManager
/** /**
* Returns health for target NPC ID * Returns health for target NPC ID
*
* @param npcId NPC id * @param npcId NPC id
* @return health or null if unknown * @return health or null if unknown
*/ */
@Nullable public int getHealth(final int npcId)
public Integer getHealth(final int npcId)
{ {
final NPCStats s = statsMap.get(npcId); final NPCStats s = statsMap.get(npcId);
if (s == null || s.getHitpoints() == -1) if (s == null || s.getHitpoints() == -1)
{ {
return null; return -1;
} }
return s.getHitpoints(); return s.getHitpoints();
} }
/**
* Returns the attack speed for target NPC ID.
*
* @param npcId NPC id
* @return attack speed in game ticks for NPC ID.
*/
public int getAttackSpeed(final int npcId)
{
final NPCStats s = statsMap.get(npcId);
if (s == null || s.getAttackSpeed() == -1)
{
return -1;
}
return s.getAttackSpeed();
}
/** /**
* Returns the exp modifier for target NPC ID based on its stats. * Returns the exp modifier for target NPC ID based on its stats.
*
* @param npcId NPC id * @param npcId NPC id
* @return npcs exp modifier. Assumes default xp rate if npc stats are unknown (returns 1) * @return npcs exp modifier. Assumes default xp rate if npc stats are unknown (returns 1)
*/ */

View File

@@ -34,6 +34,7 @@ public class NPCStats
private final int hitpoints; private final int hitpoints;
private final int combatLevel; private final int combatLevel;
private final int slayerLevel; private final int slayerLevel;
private final int attackSpeed;
private final int attackLevel; private final int attackLevel;
private final int strengthLevel; private final int strengthLevel;

View File

@@ -65,7 +65,7 @@ class OpponentInfoOverlay extends Overlay
private final PanelComponent panelComponent = new PanelComponent(); private final PanelComponent panelComponent = new PanelComponent();
private Integer lastMaxHealth; private int lastMaxHealth;
private int lastRatio = 0; private int lastRatio = 0;
private int lastHealthScale = 0; private int lastHealthScale = 0;
private String opponentName; private String opponentName;
@@ -111,7 +111,7 @@ class OpponentInfoOverlay extends Overlay
lastHealthScale = opponent.getHealth(); lastHealthScale = opponent.getHealth();
opponentName = Text.removeTags(opponent.getName()); opponentName = Text.removeTags(opponent.getName());
lastMaxHealth = null; lastMaxHealth = -1;
if (opponent instanceof NPC) if (opponent instanceof NPC)
{ {
lastMaxHealth = npcManager.getHealth(((NPC) opponent).getId()); lastMaxHealth = npcManager.getHealth(((NPC) opponent).getId());
@@ -167,7 +167,7 @@ class OpponentInfoOverlay extends Overlay
final HitpointsDisplayStyle displayStyle = opponentInfoConfig.hitpointsDisplayStyle(); final HitpointsDisplayStyle displayStyle = opponentInfoConfig.hitpointsDisplayStyle();
if ((displayStyle == HitpointsDisplayStyle.HITPOINTS || displayStyle == HitpointsDisplayStyle.BOTH) if ((displayStyle == HitpointsDisplayStyle.HITPOINTS || displayStyle == HitpointsDisplayStyle.BOTH)
&& lastMaxHealth != null) && lastMaxHealth != -1)
{ {
// This is the reverse of the calculation of healthRatio done by the server // This is the reverse of the calculation of healthRatio done by the server
// which is: healthRatio = 1 + (healthScale - 1) * health / maxHealth (if health > 0, 0 otherwise) // which is: healthRatio = 1 + (healthScale - 1) * health / maxHealth (if health > 0, 0 otherwise)

View File

@@ -98,9 +98,9 @@ class TargetWeaknessOverlay extends Overlay
final int healthScale = target.getHealth(); final int healthScale = target.getHealth();
final int healthRatio = target.getHealthRatio(); final int healthRatio = target.getHealthRatio();
final Integer maxHealth = npcManager.getHealth(target.getId()); final int maxHealth = npcManager.getHealth(target.getId());
if (healthRatio < 0 || healthScale <= 0 || maxHealth == null) if (healthRatio < 0 || healthScale <= 0 || maxHealth == -1)
{ {
return -1; return -1;
} }

View File

@@ -1,46 +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.ticktimers;
import java.awt.Font;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum FontStyle
{
BOLD("Bold", Font.BOLD),
ITALIC("Italic", Font.ITALIC),
PLAIN("Plain", Font.PLAIN);
private String name;
private int font;
@Override
public String toString()
{
return getName();
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
* Copyright (c) 2019, Ganom <https://github.com/Ganom> * Copyright (c) 2019, Ganom <https://github.com/Ganom>
* Copyright (c) 2019, Lucas <https://github.com/lucwousin>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -25,65 +25,125 @@
*/ */
package net.runelite.client.plugins.ticktimers; package net.runelite.client.plugins.ticktimers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.awt.Color; import java.awt.Color;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import net.runelite.api.Actor; import net.runelite.api.Actor;
import net.runelite.api.AnimationID;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition; import net.runelite.api.NPCDefinition;
import net.runelite.api.NpcID;
import net.runelite.api.Prayer;
@Getter
class NPCContainer class NPCContainer
{ {
@Getter
private NPC npc; private NPC npc;
@Getter
private int npcIndex; private int npcIndex;
@Getter
private String npcName; private String npcName;
@Getter
private int npcSize; private int npcSize;
private ImmutableSet<Integer> animations;
private int attackSpeed;
@Setter @Setter
@Getter private int ticksUntilAttack;
private int TicksUntilAttack;
@Setter @Setter
@Getter
private int npcSpeed;
@Setter
@Getter
private Actor npcInteracting; private Actor npcInteracting;
@Setter @Setter
@Getter private AttackStyle attackStyle;
private Attackstyle attackStyle;
NPCContainer(NPC npc) NPCContainer(NPC npc, int attackSpeed)
{ {
this.npc = npc; this.npc = npc;
this.npcName = npc.getName(); this.npcName = npc.getName();
this.npcIndex = npc.getIndex(); this.npcIndex = npc.getIndex();
this.npcInteracting = npc.getInteracting(); this.npcInteracting = npc.getInteracting();
this.npcSpeed = 0; this.attackStyle = AttackStyle.UNKNOWN;
this.attackStyle = Attackstyle.UNKNOWN; this.attackSpeed = attackSpeed;
this.TicksUntilAttack = 0; this.ticksUntilAttack = -1;
final NPCDefinition composition = npc.getTransformedDefinition(); final NPCDefinition composition = npc.getTransformedDefinition();
BossMonsters monster = BossMonsters.of(npc.getId());
if (monster == null)
{
throw new IllegalStateException();
}
this.animations = monster.animations;
this.attackStyle = monster.attackStyle;
if (composition != null) if (composition != null)
{ {
this.npcSize = composition.getSize(); this.npcSize = composition.getSize();
} }
} }
@RequiredArgsConstructor
enum BossMonsters
{
SERGEANT_STRONGSTACK(NpcID.SERGEANT_STRONGSTACK, AttackStyle.MELEE, ImmutableSet.of(AnimationID.MINION_AUTO1, AnimationID.MINION_AUTO2, AnimationID.MINION_AUTO3)),
SERGEANT_STEELWILL(NpcID.SERGEANT_STEELWILL, AttackStyle.MAGE, ImmutableSet.of(AnimationID.MINION_AUTO1, AnimationID.MINION_AUTO2, AnimationID.MINION_AUTO3)),
SERGEANT_GRIMSPIKE(NpcID.SERGEANT_GRIMSPIKE, AttackStyle.RANGE, ImmutableSet.of(AnimationID.MINION_AUTO1, AnimationID.MINION_AUTO2, AnimationID.MINION_AUTO4)),
GENERAL_GRAARDOR(NpcID.GENERAL_GRAARDOR, AttackStyle.MELEE, ImmutableSet.of(AnimationID.GENERAL_AUTO1, AnimationID.GENERAL_AUTO2, AnimationID.GENERAL_AUTO3)),
TSTANON_KARLAK(NpcID.TSTANON_KARLAK, AttackStyle.MELEE, ImmutableSet.of(AnimationID.ZAMMY_GENERIC_AUTO)),
BALFRUG_KREEYATH(NpcID.BALFRUG_KREEYATH, AttackStyle.MAGE, ImmutableSet.of(AnimationID.ZAMMY_GENERIC_AUTO, AnimationID.BALFRUG_AUTO)),
ZAKLN_GRITCH(NpcID.ZAKLN_GRITCH, AttackStyle.RANGE, ImmutableSet.of(AnimationID.ZAMMY_GENERIC_AUTO, AnimationID.ZAKL_AUTO)),
KRIL_TSUTSAROTH(NpcID.KRIL_TSUTSAROTH, AttackStyle.UNKNOWN, ImmutableSet.of(AnimationID.KRIL_SPEC, AnimationID.KRIL_AUTO)),
STARLIGHT(NpcID.STARLIGHT, AttackStyle.MELEE, ImmutableSet.of(AnimationID.STARLIGHT_AUTO)),
GROWLER(NpcID.GROWLER, AttackStyle.MAGE, ImmutableSet.of(AnimationID.GROWLER_AUTO)),
BREE(NpcID.BREE, AttackStyle.RANGE, ImmutableSet.of(AnimationID.BREE_AUTO)),
COMMANDER_ZILYANA(NpcID.COMMANDER_ZILYANA, AttackStyle.UNKNOWN, ImmutableSet.of(AnimationID.ZILYANA_AUTO, AnimationID.ZILYANA_MELEE_AUTO, AnimationID.ZILYANA_SPEC)),
FLIGHT_KILISA(NpcID.FLIGHT_KILISA, AttackStyle.MELEE, ImmutableSet.of(AnimationID.KILISA_AUTO)),
FLOCKLEADER_GEERIN(NpcID.FLOCKLEADER_GEERIN, AttackStyle.MAGE, ImmutableSet.of(AnimationID.GEERIN_AUTO, AnimationID.GEERIN_FLINCH)),
WINGMAN_SKREE(NpcID.WINGMAN_SKREE, AttackStyle.RANGE, ImmutableSet.of(AnimationID.SKREE_AUTO)),
KREEARRA(NpcID.KREEARRA, AttackStyle.RANGE, ImmutableSet.of(AnimationID.KREE_RANGED)),
DAGANNOTH_REX(NpcID.DAGANNOTH_REX, AttackStyle.MAGE, ImmutableSet.of(AnimationID.DAG_REX)),
DAGANNOTH_SUPREME(NpcID.DAGANNOTH_SUPREME, AttackStyle.RANGE, ImmutableSet.of(AnimationID.DAG_SUPREME)),
DAGANNOTH_PRIME(NpcID.DAGANNOTH_PRIME, AttackStyle.MAGE, ImmutableSet.of(AnimationID.DAG_PRIME));
private static ImmutableMap<Integer, BossMonsters> idMap;
static
{
ImmutableMap.Builder<Integer, BossMonsters> builder = ImmutableMap.builder();
for (BossMonsters monster : values())
{
builder.put(monster.npcID, monster);
}
idMap = builder.build();
}
private final int npcID;
private final AttackStyle attackStyle;
private final ImmutableSet<Integer> animations;
static BossMonsters of(int npcID)
{
return idMap.get(npcID);
}
}
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
public enum Attackstyle public enum AttackStyle
{ {
MAGE("Mage", Color.CYAN), MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC),
RANGE("Range", Color.GREEN), RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES),
MELEE("Melee", Color.RED), MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE),
UNKNOWN("Unknown", Color.WHITE); UNKNOWN("Unknown", Color.WHITE, null);
private String name = ""; private String name;
private Color color; private Color color;
private Prayer prayer;
} }
} }

View File

@@ -23,6 +23,9 @@
*/ */
package net.runelite.client.plugins.ticktimers; package net.runelite.client.plugins.ticktimers;
import java.awt.Font;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
@@ -34,6 +37,54 @@ public interface TickTimersConfig extends Config
{ {
@ConfigItem( @ConfigItem(
position = 0, position = 0,
keyName = "mainConfig",
name = "Main Config",
description = ""
)
default Stub mainConfig()
{
return new Stub();
}
@ConfigItem(
position = 1,
keyName = "prayerWidgetHelper",
name = "Prayer Widget Helper",
description = "Shows you which prayer to click and the time until click.",
parent = "mainConfig"
)
default boolean showPrayerWidgetHelper()
{
return false;
}
@ConfigItem(
position = 2,
keyName = "showHitSquares",
name = "Show Hit Squares",
description = "Shows you where the melee bosses can hit you from.",
parent = "mainConfig"
)
default boolean showHitSquares()
{
return false;
}
@ConfigItem(
position = 3,
keyName = "changeTickColor",
name = "Change Tick Color",
description = "If this is enabled, it will change the tick color to white" +
"<br> at 1 tick remaining, signaling you to swap.",
parent = "mainConfig"
)
default boolean changeTickColor()
{
return false;
}
@ConfigItem(
position = 4,
keyName = "bosses", keyName = "bosses",
name = "Bosses", name = "Bosses",
description = "" description = ""
@@ -44,19 +95,31 @@ public interface TickTimersConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 1, position = 5,
keyName = "graardor", keyName = "gwd",
name = "General Graardor", name = "God Wars Dungeon",
description = "Show tick timers for General Graardor", description = "Show tick timers for GWD Bosses. This must be enabled before you zone in.",
parent = "bosses" parent = "bosses"
) )
default boolean graardor() default boolean gwd()
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
position = 22, position = 6,
keyName = "dks",
name = "Dagannoth Kings",
description = "Show tick timers for Dagannoth Kings. This must be enabled before you zone in.",
parent = "bosses"
)
default boolean dks()
{
return true;
}
@ConfigItem(
position = 7,
keyName = "text", keyName = "text",
name = "Text", name = "Text",
description = "" description = ""
@@ -67,7 +130,7 @@ public interface TickTimersConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 23, position = 8,
keyName = "fontStyle", keyName = "fontStyle",
name = "Font Style", name = "Font Style",
description = "Plain | Bold | Italics", description = "Plain | Bold | Italics",
@@ -75,7 +138,7 @@ public interface TickTimersConfig extends Config
) )
default FontStyle fontStyle() default FontStyle fontStyle()
{ {
return FontStyle.PLAIN; return FontStyle.BOLD;
} }
@Range( @Range(
@@ -83,7 +146,7 @@ public interface TickTimersConfig extends Config
max = 40 max = 40
) )
@ConfigItem( @ConfigItem(
position = 24, position = 9,
keyName = "textSize", keyName = "textSize",
name = "Text Size", name = "Text Size",
description = "Text Size for Timers.", description = "Text Size for Timers.",
@@ -95,7 +158,7 @@ public interface TickTimersConfig extends Config
} }
@ConfigItem( @ConfigItem(
position = 25, position = 10,
keyName = "shadows", keyName = "shadows",
name = "Shadows", name = "Shadows",
description = "Adds Shadows to text.", description = "Adds Shadows to text.",
@@ -105,4 +168,22 @@ public interface TickTimersConfig extends Config
{ {
return false; return false;
} }
@Getter
@AllArgsConstructor
enum FontStyle
{
BOLD("Bold", Font.BOLD),
ITALIC("Italic", Font.ITALIC),
PLAIN("Plain", Font.PLAIN);
private String name;
private int font;
@Override
public String toString()
{
return getName();
}
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, ganom <https://github.com/Ganom> * Copyright (c) 2019, Ganom <https://github.com/Ganom>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -24,13 +24,13 @@
package net.runelite.client.plugins.ticktimers; package net.runelite.client.plugins.ticktimers;
import com.google.inject.Provides; import com.google.inject.Provides;
import java.util.HashMap; import java.util.Arrays;
import java.util.Map; import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.NPC; import net.runelite.api.NPC;
@@ -41,11 +41,11 @@ import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.NpcSpawned;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.NPCManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor( @PluginDescriptor(
name = "Boss Tick Timers", name = "Boss Tick Timers",
@@ -59,21 +59,24 @@ import org.apache.commons.lang3.ArrayUtils;
public class TickTimersPlugin extends Plugin public class TickTimersPlugin extends Plugin
{ {
private static final int GENERAL_REGION = 11347; private static final int GENERAL_REGION = 11347;
private static final int ARMA_REGION = 11346;
private static final int SARA_REGION = 11601;
private static final int ZAMMY_REGION = 11603;
private static final int WATERBITH_REGION = 11589;
@Inject @Inject
private Client client; private Client client;
@Inject @Inject
private OverlayManager overlayManager; private OverlayManager overlayManager;
@Inject @Inject
private TimersOverlay timersOverlay; private TimersOverlay timersOverlay;
@Inject @Inject
private TickTimersConfig config; private TickTimersConfig config;
@Inject
private NPCManager npcManager;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> npcContainer = new HashMap<>(); private Set<NPCContainer> npcContainer = new HashSet<>();
private boolean validRegion;
@Provides @Provides
TickTimersConfig getConfig(ConfigManager configManager) TickTimersConfig getConfig(ConfigManager configManager)
@@ -91,41 +94,71 @@ public class TickTimersPlugin extends Plugin
public void shutDown() public void shutDown()
{ {
npcContainer.clear(); npcContainer.clear();
overlayManager.remove(timersOverlay);
validRegion = false;
} }
@Subscribe @Subscribe
public void onGameStateChanged(GameStateChanged gameStateChanged) public void onGameStateChanged(GameStateChanged gameStateChanged)
{ {
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
{
if (isInGeneralRegion())
{
overlayManager.add(timersOverlay);
}
else
{
overlayManager.remove(timersOverlay);
}
}
if (gameStateChanged.getGameState() != GameState.LOGGED_IN) if (gameStateChanged.getGameState() != GameState.LOGGED_IN)
{ {
return; return;
} }
if (regionCheck())
{
validRegion = true;
overlayManager.add(timersOverlay);
}
else
{
validRegion = false;
overlayManager.remove(timersOverlay);
}
npcContainer.clear(); npcContainer.clear();
} }
@Subscribe @Subscribe
public void onNpcSpawned(NpcSpawned event) public void onNpcSpawned(NpcSpawned event)
{ {
if (!validRegion)
{
return;
}
NPC npc = event.getNpc(); NPC npc = event.getNpc();
switch (npc.getId()) switch (npc.getId())
{ {
case NpcID.SERGEANT_STRONGSTACK: case NpcID.SERGEANT_STRONGSTACK:
case NpcID.SERGEANT_STEELWILL: case NpcID.SERGEANT_STEELWILL:
case NpcID.SERGEANT_GRIMSPIKE: case NpcID.SERGEANT_GRIMSPIKE:
case NpcID.GENERAL_GRAARDOR: case NpcID.GENERAL_GRAARDOR:
case NpcID.GENERAL_GRAARDOR_6494: case NpcID.TSTANON_KARLAK:
npcContainer.put(npc, new NPCContainer(npc)); case NpcID.BALFRUG_KREEYATH:
case NpcID.ZAKLN_GRITCH:
case NpcID.KRIL_TSUTSAROTH:
case NpcID.STARLIGHT:
case NpcID.BREE:
case NpcID.GROWLER:
case NpcID.COMMANDER_ZILYANA:
case NpcID.FLIGHT_KILISA:
case NpcID.FLOCKLEADER_GEERIN:
case NpcID.WINGMAN_SKREE:
case NpcID.KREEARRA:
if (config.gwd())
{
npcContainer.add(new NPCContainer(npc, npcManager.getAttackSpeed(npc.getId())));
}
break;
case NpcID.DAGANNOTH_REX:
case NpcID.DAGANNOTH_SUPREME:
case NpcID.DAGANNOTH_PRIME:
if (config.dks())
{
npcContainer.add(new NPCContainer(npc, npcManager.getAttackSpeed(npc.getId())));
}
break; break;
} }
} }
@@ -133,92 +166,76 @@ public class TickTimersPlugin extends Plugin
@Subscribe @Subscribe
public void onNpcDespawned(NpcDespawned event) public void onNpcDespawned(NpcDespawned event)
{ {
if (npcContainer.remove(event.getNpc()) != null && !npcContainer.isEmpty()) if (!validRegion)
{ {
npcContainer.remove(event.getNpc()); return;
}
NPC npc = event.getNpc();
switch (npc.getId())
{
case NpcID.SERGEANT_STRONGSTACK:
case NpcID.SERGEANT_STEELWILL:
case NpcID.SERGEANT_GRIMSPIKE:
case NpcID.GENERAL_GRAARDOR:
case NpcID.TSTANON_KARLAK:
case NpcID.BALFRUG_KREEYATH:
case NpcID.ZAKLN_GRITCH:
case NpcID.KRIL_TSUTSAROTH:
case NpcID.STARLIGHT:
case NpcID.BREE:
case NpcID.GROWLER:
case NpcID.COMMANDER_ZILYANA:
case NpcID.FLIGHT_KILISA:
case NpcID.FLOCKLEADER_GEERIN:
case NpcID.WINGMAN_SKREE:
case NpcID.KREEARRA:
case NpcID.DAGANNOTH_REX:
case NpcID.DAGANNOTH_SUPREME:
case NpcID.DAGANNOTH_PRIME:
npcContainer.removeIf(c -> c.getNpc() == npc);
break;
} }
} }
@Subscribe @Subscribe
public void onGameTick(GameTick Event) public void onGameTick(GameTick Event)
{ {
if (config.graardor()) if (!validRegion)
{ {
graardorHandler(); return;
} }
handleBosses();
} }
private void graardorHandler() private void handleBosses()
{ {
for (NPCContainer npcs : getNpcContainer().values()) for (NPCContainer npcs : getNpcContainer())
{ {
switch (npcs.getNpc().getId()) if (npcs.getTicksUntilAttack() >= 0)
{ {
case NpcID.SERGEANT_STRONGSTACK: npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1);
npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1); }
npcs.setAttackStyle(NPCContainer.Attackstyle.MELEE);
switch (npcs.getNpc().getAnimation()) for (int anims : npcs.getAnimations())
{
if (anims == npcs.getNpc().getAnimation())
{
if (npcs.getTicksUntilAttack() < 1)
{ {
case AnimationID.MINION_AUTO1: npcs.setTicksUntilAttack(npcs.getAttackSpeed());
case AnimationID.MINION_AUTO2:
if (npcs.getTicksUntilAttack() < 1)
{
npcs.setTicksUntilAttack(5);
}
break;
} }
break; }
case NpcID.SERGEANT_STEELWILL:
npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1);
npcs.setAttackStyle(NPCContainer.Attackstyle.MAGE);
switch (npcs.getNpc().getAnimation())
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
case AnimationID.MINION_AUTO3:
if (npcs.getTicksUntilAttack() < 1)
{
npcs.setTicksUntilAttack(5);
}
break;
}
case NpcID.SERGEANT_GRIMSPIKE:
npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1);
npcs.setAttackStyle(NPCContainer.Attackstyle.RANGE);
switch (npcs.getNpc().getAnimation())
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
case AnimationID.MINION_AUTO4:
if (npcs.getTicksUntilAttack() < 1)
{
npcs.setTicksUntilAttack(5);
}
break;
}
break;
case NpcID.GENERAL_GRAARDOR:
case NpcID.GENERAL_GRAARDOR_6494:
npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1);
npcs.setAttackStyle(NPCContainer.Attackstyle.MELEE);
switch (npcs.getNpc().getAnimation())
{
case AnimationID.GENERAL_AUTO1:
case AnimationID.GENERAL_AUTO2:
case AnimationID.GENERAL_AUTO3:
if (npcs.getTicksUntilAttack() < 1)
{
npcs.setTicksUntilAttack(6);
}
break;
}
break;
} }
} }
} }
private boolean isInGeneralRegion() private boolean regionCheck()
{ {
return ArrayUtils.contains(client.getMapRegions(), GENERAL_REGION); return Arrays.stream(client.getMapRegions()).anyMatch(
x -> x == ARMA_REGION || x == GENERAL_REGION || x == ZAMMY_REGION || x == SARA_REGION || x == WATERBITH_REGION
);
} }
} }

View File

@@ -24,19 +24,17 @@
*/ */
package net.runelite.client.plugins.ticktimers; package net.runelite.client.plugins.ticktimers;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Polygon; import java.awt.Rectangle;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.Perspective;
import net.runelite.api.Point; import net.runelite.api.Point;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldArea;
import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPosition;
@@ -63,67 +61,91 @@ public class TimersOverlay extends Overlay
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
Color tickcolor; for (NPCContainer npc : plugin.getNpcContainer())
for (NPCContainer npcs : plugin.getNpcContainer().values())
{ {
renderNpcOverlay(graphics, npcs.getNpc(), npcs.getAttackStyle().getColor(), 100, 10); if (npc.getNpc() == null)
final int ticksLeft = npcs.getTicksUntilAttack();
if (ticksLeft > 0)
{ {
if (ticksLeft == 1) continue;
}
int ticksLeft = npc.getTicksUntilAttack();
final List<WorldPoint> hitSquares = getHitSquares(npc.getNpc().getWorldLocation(), npc.getNpcSize(), 1, false);
final NPCContainer.AttackStyle attackStyle = npc.getAttackStyle();
if (config.showHitSquares() && attackStyle.getName().equals("Melee"))
{
for (WorldPoint p : hitSquares)
{ {
tickcolor = npcs.getAttackStyle().getColor(); OverlayUtil.drawTile(graphics, client, p, client.getLocalPlayer().getWorldLocation(), attackStyle.getColor(), 0, 0, 50);
} }
else }
if (ticksLeft <= 0)
{
continue;
}
final String ticksLeftStr = String.valueOf(ticksLeft);
final int font = config.fontStyle().getFont();
final boolean shadows = config.shadows();
Color color = (ticksLeft <= 1 ? Color.WHITE : attackStyle.getColor());
if (!config.changeTickColor())
{
color = attackStyle.getColor();
}
final Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, Integer.toString(ticksLeft), 0);
OverlayUtil.renderTextLocation(graphics, ticksLeftStr, config.textSize(), font, color, canvasPoint, shadows, 0);
if (config.showPrayerWidgetHelper() && attackStyle.getPrayer() != null)
{
Rectangle bounds = OverlayUtil.renderPrayerOverlay(graphics, client, attackStyle.getPrayer(), color);
if (bounds != null)
{ {
tickcolor = Color.WHITE; renderTextLocation(graphics, ticksLeftStr, 16, config.fontStyle().getFont(), color, centerPoint(bounds), shadows);
} }
final String ticksLeftStr = String.valueOf(ticksLeft);
Point canvasPoint = npcs.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0);
renderTextLocation(graphics, ticksLeftStr, config.textSize(), config.fontStyle().getFont(), tickcolor, canvasPoint);
} }
} }
return null; return null;
} }
private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineAlpha, int fillAlpha) private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint, boolean shadows)
{
int size = 1;
NPCDefinition composition = actor.getTransformedDefinition();
if (composition != null)
{
size = composition.getSize();
}
LocalPoint lp = actor.getLocalLocation();
Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
if (tilePoly != null)
{
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha));
graphics.setStroke(new BasicStroke(2));
graphics.draw(tilePoly);
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha));
graphics.fill(tilePoly);
}
}
private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint)
{ {
graphics.setFont(new Font("Arial", fontStyle, fontSize)); graphics.setFont(new Font("Arial", fontStyle, fontSize));
if (canvasPoint != null) if (canvasPoint != null)
{ {
final Point canvasCenterPoint = new Point( final Point canvasCenterPoint = new Point(
canvasPoint.getX(), canvasPoint.getX() - 3,
canvasPoint.getY()); canvasPoint.getY() + 6);
final Point canvasCenterPoint_shadow = new Point( final Point canvasCenterPoint_shadow = new Point(
canvasPoint.getX() + 1, canvasPoint.getX() - 2,
canvasPoint.getY() + 1); canvasPoint.getY() + 7);
if (config.shadows()) if (shadows)
{ {
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK);
} }
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor);
} }
} }
private List<WorldPoint> getHitSquares(WorldPoint npcLoc, int npcSize, int thickness, boolean includeUnder)
{
List<WorldPoint> little = new WorldArea(npcLoc, npcSize, npcSize).toWorldPointList();
List<WorldPoint> big = new WorldArea(npcLoc.getX() - thickness, npcLoc.getY() - thickness, npcSize + (thickness * 2), npcSize + (thickness * 2), npcLoc.getPlane()).toWorldPointList();
if (!includeUnder)
{
big.removeIf(little::contains);
}
return big;
}
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

@@ -126,9 +126,9 @@ class XpState
* @param npc currently interacted NPC * @param npc currently interacted NPC
* @param npcHealth health of currently interacted NPC * @param npcHealth health of currently interacted NPC
*/ */
void updateNpcExperience(Skill skill, NPC npc, Integer npcHealth) void updateNpcExperience(Skill skill, NPC npc, int npcHealth)
{ {
if (npc == null || npc.getCombatLevel() <= 0 || npcHealth == null) if (npc == null || npc.getCombatLevel() <= 0 || npcHealth == -1)
{ {
return; return;
} }
@@ -170,11 +170,11 @@ class XpState
* @param npcHealth max health of npc that just died * @param npcHealth max health of npc that just died
* @return UPDATED in case new kill was successfully added * @return UPDATED in case new kill was successfully added
*/ */
XpUpdateResult updateNpcKills(Skill skill, NPC npc, Integer npcHealth) XpUpdateResult updateNpcKills(Skill skill, NPC npc, int npcHealth)
{ {
XpStateSingle state = getSkill(skill); XpStateSingle state = getSkill(skill);
if (state.getXpGained() <= 0 || npcHealth == null || npc != interactedNPC) if (state.getXpGained() <= 0 || npcHealth == -1 || npc != interactedNPC)
{ {
return XpUpdateResult.NO_CHANGE; return XpUpdateResult.NO_CHANGE;
} }

View File

@@ -28,8 +28,10 @@ import com.google.common.base.Strings;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Polygon; import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Stroke; import java.awt.Stroke;
import java.awt.geom.Area; import java.awt.geom.Area;
@@ -38,8 +40,11 @@ import net.runelite.api.Actor;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Perspective; import net.runelite.api.Perspective;
import net.runelite.api.Point; import net.runelite.api.Point;
import net.runelite.api.Prayer;
import net.runelite.api.TileObject; import net.runelite.api.TileObject;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.widgets.Widget;
/** /**
@@ -259,8 +264,7 @@ public class OverlayUtil
return result; return result;
} }
public static void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, public static void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, BufferedImage image, int yOffset, int xOffset)
BufferedImage image, int yOffset, int xOffset)
{ {
Point textLocation = new Point(actor.getConvexHull().getBounds().x + xOffset, Point textLocation = new Point(actor.getConvexHull().getBounds().x + xOffset,
actor.getConvexHull().getBounds().y + yOffset); actor.getConvexHull().getBounds().y + yOffset);
@@ -271,4 +275,69 @@ public class OverlayUtil
textLocation = new Point(textLocation.getX() + xOffset, textLocation.getY() + image.getHeight() - yOffset); textLocation = new Point(textLocation.getX() + xOffset, textLocation.getY() + image.getHeight() - yOffset);
renderTextLocation(graphics, textLocation, text, color); renderTextLocation(graphics, textLocation, text, color);
} }
public static void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint, boolean shadows, int yOffset)
{
graphics.setFont(new Font("Arial", fontStyle, fontSize));
if (canvasPoint != null)
{
final Point canvasCenterPoint = new Point(
canvasPoint.getX(),
canvasPoint.getY() + yOffset);
final Point canvasCenterPoint_shadow = new Point(
canvasPoint.getX() + 1,
canvasPoint.getY() + 1);
if (shadows)
{
renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK);
}
renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor);
}
}
public static void drawTile(Graphics2D graphics, Client client, WorldPoint point, WorldPoint playerPoint, Color color, int strokeWidth, int outlineAlpha, int fillAlpha)
{
if (point.distanceTo(playerPoint) >= 32)
{
return;
}
LocalPoint lp = LocalPoint.fromWorld(client, point);
if (lp == null)
{
return;
}
Polygon poly = Perspective.getCanvasTilePoly(client, lp);
if (poly == null)
{
return;
}
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha));
graphics.setStroke(new BasicStroke(strokeWidth));
graphics.draw(poly);
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha));
graphics.fill(poly);
}
public static Rectangle renderPrayerOverlay(Graphics2D graphics, Client client, Prayer prayer, Color color)
{
Widget widget = client.getWidget(prayer.getWidgetInfo());
if (widget == null || widget.isHidden())
{
return null;
}
Rectangle bounds = widget.getBounds();
renderPolygon(graphics, rectangleToPolygon(bounds), color);
return bounds;
}
private static Polygon rectangleToPolygon(Rectangle rect)
{
int[] xpoints = {rect.x, rect.x + rect.width, rect.x + rect.width, rect.x};
int[] ypoints = {rect.y, rect.y, rect.y + rect.height, rect.y + rect.height};
return new Polygon(xpoints, ypoints, 4);
}
} }

File diff suppressed because it is too large Load Diff