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

@@ -157,7 +157,7 @@ public final class AnimationID
public static final int HOME_MAKE_TABLET = 4067;
public static final int THIEVING_STALL = 832;
public static final int PICKPOCKET_SUCCESS = 881;
//block animations for players and perhaps npcs as well?
public static final int BLOCK_DEFENDER = 4177;
public static final int BLOCK_NO_SHIELD = 420;
@@ -252,7 +252,7 @@ public final class AnimationID
public static final int HYDRA_RANGED_4 = 8255;
public static final int HYDRA_4_1 = 8257;
public static final int HYDRA_4_2 = 8258;
// INFERNO animations
public static final int JAL_NIB = 7574;
public static final int JAL_MEJRAH = 7578;
@@ -278,4 +278,31 @@ public final class AnimationID
public static final int GENERAL_AUTO1 = 7018;
public static final int GENERAL_AUTO2 = 7020;
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;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.widgets.WidgetInfo;
/**
* An enumeration of different prayer spells.
*/
@Getter
@AllArgsConstructor
public enum Prayer
{
/**
* 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(Varbits.PRAYER_MYSTIC_MIGHT, 20.0),
MYSTIC_MIGHT(Varbits.PRAYER_MYSTIC_MIGHT, 20.0, WidgetInfo.PRAYER_MYSTIC_MIGHT),
/**
* Retribution (Level 46).
*/
RETRIBUTION(Varbits.PRAYER_RETRIBUTION, 5.0),
RETRIBUTION(Varbits.PRAYER_RETRIBUTION, 5.0, WidgetInfo.PRAYER_RETRIBUTION),
/**
* Redemption (Level 49).
*/
REDEMPTION(Varbits.PRAYER_REDEMPTION, 10.0),
REDEMPTION(Varbits.PRAYER_REDEMPTION, 10.0, WidgetInfo.PRAYER_REDEMPTION),
/**
* 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(Varbits.PRAYER_CHIVALRY, 40.0),
CHIVALRY(Varbits.PRAYER_CHIVALRY, 40.0, WidgetInfo.PRAYER_CHIVALRY),
/**
* 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(Varbits.PRAYER_PRESERVE, 60.0 / 18),
PRESERVE(Varbits.PRAYER_PRESERVE, 60.0 / 18, WidgetInfo.PRAYER_PRESERVE),
/**
* 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(Varbits.PRAYER_AUGURY, 40.0);
private final Varbits varbit;
private final double drainRate;
Prayer(Varbits varbit, double drainRate)
{
this.varbit = varbit;
this.drainRate = drainRate;
}
AUGURY(Varbits.PRAYER_AUGURY, 40.0, WidgetInfo.PRAYER_AUGURY);
/**
* Gets the varbit that stores whether the prayer is active or not.
*
* @return the prayer active varbit
*/
public Varbits getVarbit()
{
return varbit;
}
private final Varbits varbit;
/**
* Gets the prayer drain rate (measured in pray points/minute)
*
* @return the prayer drain rate
*/
public double getDrainRate()
{
return drainRate;
}
}
private final double 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
*
* @param npcId NPC id
* @return the {@link NPCStats} or null if unknown
*/
@@ -70,23 +71,41 @@ public class NPCManager
/**
* Returns health for target NPC ID
*
* @param npcId NPC id
* @return health or null if unknown
*/
@Nullable
public Integer getHealth(final int npcId)
public int getHealth(final int npcId)
{
final NPCStats s = statsMap.get(npcId);
if (s == null || s.getHitpoints() == -1)
{
return null;
return -1;
}
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.
*
* @param npcId NPC id
* @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 combatLevel;
private final int slayerLevel;
private final int attackSpeed;
private final int attackLevel;
private final int strengthLevel;

View File

@@ -65,7 +65,7 @@ class OpponentInfoOverlay extends Overlay
private final PanelComponent panelComponent = new PanelComponent();
private Integer lastMaxHealth;
private int lastMaxHealth;
private int lastRatio = 0;
private int lastHealthScale = 0;
private String opponentName;
@@ -111,7 +111,7 @@ class OpponentInfoOverlay extends Overlay
lastHealthScale = opponent.getHealth();
opponentName = Text.removeTags(opponent.getName());
lastMaxHealth = null;
lastMaxHealth = -1;
if (opponent instanceof NPC)
{
lastMaxHealth = npcManager.getHealth(((NPC) opponent).getId());
@@ -167,7 +167,7 @@ class OpponentInfoOverlay extends Overlay
final HitpointsDisplayStyle displayStyle = opponentInfoConfig.hitpointsDisplayStyle();
if ((displayStyle == HitpointsDisplayStyle.HITPOINTS || displayStyle == HitpointsDisplayStyle.BOTH)
&& lastMaxHealth != null)
&& lastMaxHealth != -1)
{
// 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)

View File

@@ -98,9 +98,9 @@ class TargetWeaknessOverlay extends Overlay
final int healthScale = target.getHealth();
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;
}

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, Lucas <https://github.com/lucwousin>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,65 +25,125 @@
*/
package net.runelite.client.plugins.ticktimers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.awt.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import net.runelite.api.Actor;
import net.runelite.api.AnimationID;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
import net.runelite.api.NpcID;
import net.runelite.api.Prayer;
@Getter
class NPCContainer
{
@Getter
private NPC npc;
@Getter
private int npcIndex;
@Getter
private String npcName;
@Getter
private int npcSize;
private ImmutableSet<Integer> animations;
private int attackSpeed;
@Setter
@Getter
private int TicksUntilAttack;
private int ticksUntilAttack;
@Setter
@Getter
private int npcSpeed;
@Setter
@Getter
private Actor npcInteracting;
@Setter
@Getter
private Attackstyle attackStyle;
private AttackStyle attackStyle;
NPCContainer(NPC npc)
NPCContainer(NPC npc, int attackSpeed)
{
this.npc = npc;
this.npcName = npc.getName();
this.npcIndex = npc.getIndex();
this.npcInteracting = npc.getInteracting();
this.npcSpeed = 0;
this.attackStyle = Attackstyle.UNKNOWN;
this.TicksUntilAttack = 0;
this.attackStyle = AttackStyle.UNKNOWN;
this.attackSpeed = attackSpeed;
this.ticksUntilAttack = -1;
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)
{
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
@Getter
public enum Attackstyle
public enum AttackStyle
{
MAGE("Mage", Color.CYAN),
RANGE("Range", Color.GREEN),
MELEE("Melee", Color.RED),
UNKNOWN("Unknown", Color.WHITE);
MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC),
RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES),
MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE),
UNKNOWN("Unknown", Color.WHITE, null);
private String name = "";
private String name;
private Color color;
private Prayer prayer;
}
}

View File

@@ -23,6 +23,9 @@
*/
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.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@@ -34,6 +37,54 @@ public interface TickTimersConfig extends Config
{
@ConfigItem(
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",
name = "Bosses",
description = ""
@@ -44,19 +95,31 @@ public interface TickTimersConfig extends Config
}
@ConfigItem(
position = 1,
keyName = "graardor",
name = "General Graardor",
description = "Show tick timers for General Graardor",
position = 5,
keyName = "gwd",
name = "God Wars Dungeon",
description = "Show tick timers for GWD Bosses. This must be enabled before you zone in.",
parent = "bosses"
)
default boolean graardor()
default boolean gwd()
{
return true;
}
@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",
name = "Text",
description = ""
@@ -67,7 +130,7 @@ public interface TickTimersConfig extends Config
}
@ConfigItem(
position = 23,
position = 8,
keyName = "fontStyle",
name = "Font Style",
description = "Plain | Bold | Italics",
@@ -75,7 +138,7 @@ public interface TickTimersConfig extends Config
)
default FontStyle fontStyle()
{
return FontStyle.PLAIN;
return FontStyle.BOLD;
}
@Range(
@@ -83,7 +146,7 @@ public interface TickTimersConfig extends Config
max = 40
)
@ConfigItem(
position = 24,
position = 9,
keyName = "textSize",
name = "Text Size",
description = "Text Size for Timers.",
@@ -95,7 +158,7 @@ public interface TickTimersConfig extends Config
}
@ConfigItem(
position = 25,
position = 10,
keyName = "shadows",
name = "Shadows",
description = "Adds Shadows to text.",
@@ -105,4 +168,22 @@ public interface TickTimersConfig extends Config
{
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.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,13 +24,13 @@
package net.runelite.client.plugins.ticktimers;
import com.google.inject.Provides;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.NPC;
@@ -41,11 +41,11 @@ import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.NPCManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.overlay.OverlayManager;
import org.apache.commons.lang3.ArrayUtils;
@PluginDescriptor(
name = "Boss Tick Timers",
@@ -59,21 +59,24 @@ import org.apache.commons.lang3.ArrayUtils;
public class TickTimersPlugin extends Plugin
{
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
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private TimersOverlay timersOverlay;
@Inject
private TickTimersConfig config;
@Inject
private NPCManager npcManager;
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> npcContainer = new HashMap<>();
private Set<NPCContainer> npcContainer = new HashSet<>();
private boolean validRegion;
@Provides
TickTimersConfig getConfig(ConfigManager configManager)
@@ -91,41 +94,71 @@ public class TickTimersPlugin extends Plugin
public void shutDown()
{
npcContainer.clear();
overlayManager.remove(timersOverlay);
validRegion = false;
}
@Subscribe
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)
{
return;
}
if (regionCheck())
{
validRegion = true;
overlayManager.add(timersOverlay);
}
else
{
validRegion = false;
overlayManager.remove(timersOverlay);
}
npcContainer.clear();
}
@Subscribe
public void onNpcSpawned(NpcSpawned event)
{
if (!validRegion)
{
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.GENERAL_GRAARDOR_6494:
npcContainer.put(npc, new NPCContainer(npc));
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:
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;
}
}
@@ -133,92 +166,76 @@ public class TickTimersPlugin extends Plugin
@Subscribe
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
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.setAttackStyle(NPCContainer.Attackstyle.MELEE);
switch (npcs.getNpc().getAnimation())
npcs.setTicksUntilAttack(npcs.getTicksUntilAttack() - 1);
}
for (int anims : npcs.getAnimations())
{
if (anims == npcs.getNpc().getAnimation())
{
if (npcs.getTicksUntilAttack() < 1)
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
if (npcs.getTicksUntilAttack() < 1)
{
npcs.setTicksUntilAttack(5);
}
break;
npcs.setTicksUntilAttack(npcs.getAttackSpeed());
}
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;
import java.awt.BasicStroke;
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.util.List;
import javax.inject.Inject;
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.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.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -63,67 +61,91 @@ public class TimersOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
Color tickcolor;
for (NPCContainer npcs : plugin.getNpcContainer().values())
for (NPCContainer npc : plugin.getNpcContainer())
{
renderNpcOverlay(graphics, npcs.getNpc(), npcs.getAttackStyle().getColor(), 100, 10);
final int ticksLeft = npcs.getTicksUntilAttack();
if (ticksLeft > 0)
if (npc.getNpc() == null)
{
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;
}
private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineAlpha, int fillAlpha)
{
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)
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(),
canvasPoint.getY());
canvasPoint.getX() - 3,
canvasPoint.getY() + 6);
final Point canvasCenterPoint_shadow = new Point(
canvasPoint.getX() + 1,
canvasPoint.getY() + 1);
if (config.shadows())
canvasPoint.getX() - 2,
canvasPoint.getY() + 7);
if (shadows)
{
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK);
}
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 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;
}
@@ -170,11 +170,11 @@ class XpState
* @param npcHealth max health of npc that just died
* @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);
if (state.getXpGained() <= 0 || npcHealth == null || npc != interactedNPC)
if (state.getXpGained() <= 0 || npcHealth == -1 || npc != interactedNPC)
{
return XpUpdateResult.NO_CHANGE;
}

View File

@@ -28,8 +28,10 @@ import com.google.common.base.Strings;
import java.awt.BasicStroke;
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.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Area;
@@ -38,8 +40,11 @@ import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.Perspective;
import net.runelite.api.Point;
import net.runelite.api.Prayer;
import net.runelite.api.TileObject;
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;
}
public static void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color,
BufferedImage image, int yOffset, int xOffset)
public static void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, BufferedImage image, int yOffset, int xOffset)
{
Point textLocation = new Point(actor.getConvexHull().getBounds().x + xOffset,
actor.getConvexHull().getBounds().y + yOffset);
@@ -271,4 +275,69 @@ public class OverlayUtil
textLocation = new Point(textLocation.getX() + xOffset, textLocation.getY() + image.getHeight() - yOffset);
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