Merge pull request #578 from Ganom/tt

Accurate Tick Timers for General Graardor
This commit is contained in:
Tyler Bochard
2019-06-12 21:17:14 -04:00
committed by GitHub
6 changed files with 691 additions and 0 deletions

View File

@@ -268,4 +268,13 @@ public final class AnimationID
public static final int JALTOK_JAD_RANGE_ATTACK = 7593;
public static final int TZKAL_ZUK = 7566;
public static final int JAL_MEJJAK = 2858;
//General Graardor
public static final int MINION_AUTO1 = 6154;
public static final int MINION_AUTO2 = 6156;
public static final int MINION_AUTO3 = 7071;
public static final int MINION_AUTO4 = 7073;
public static final int GENERAL_AUTO1 = 7018;
public static final int GENERAL_AUTO2 = 7020;
public static final int GENERAL_AUTO3 = 7021;
}

View File

@@ -0,0 +1,46 @@
/*
* 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

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2018, Woox <https://github.com/wooxsolo>
* 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 lombok.Getter;
import lombok.Setter;
import net.runelite.api.Actor;
import net.runelite.api.NPC;
import net.runelite.api.NPCDefinition;
class NPCContainer
{
@Getter
private NPC npc;
@Getter
private int npcIndex;
@Getter
private String npcName;
@Getter
private int npcSize;
@Setter
@Getter
private int TicksUntilAttack;
@Setter
@Getter
private int npcSpeed;
@Setter
@Getter
private Actor npcInteracting;
NPCContainer(NPC npc)
{
this.npc = npc;
this.npcName = npc.getName();
this.npcIndex = npc.getIndex();
this.npcInteracting = npc.getInteracting();
this.npcSpeed = 0;
this.TicksUntilAttack = 0;
final NPCDefinition composition = npc.getTransformedDefinition();
if (composition != null)
{
this.npcSize = composition.getSize();
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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 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("TickTimers")
public interface TickTimersConfig extends Config
{
@ConfigItem(
position = 0,
keyName = "bosses",
name = "Bosses",
description = ""
)
default Stub bosses()
{
return new Stub();
}
@ConfigItem(
position = 1,
keyName = "graardor",
name = "General Graardor",
description = "Show tick timers for General Graardor",
parent = "bosses"
)
default boolean graardor()
{
return true;
}
@ConfigItem(
position = 22,
keyName = "text",
name = "Text",
description = ""
)
default Stub text()
{
return new Stub();
}
@ConfigItem(
position = 23,
keyName = "fontStyle",
name = "Font Style",
description = "Plain | Bold | Italics",
parent = "text"
)
default FontStyle fontStyle()
{
return FontStyle.PLAIN;
}
@Range(
min = 14,
max = 40
)
@ConfigItem(
position = 24,
keyName = "textSize",
name = "Text Size",
description = "Text Size for Timers.",
parent = "text"
)
default int textSize()
{
return 32;
}
@ConfigItem(
position = 25,
keyName = "shadows",
name = "Shadows",
description = "Adds Shadows to text.",
parent = "text"
)
default boolean shadows()
{
return false;
}
}

View File

@@ -0,0 +1,258 @@
/*
* 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 com.google.inject.Provides;
import java.util.HashMap;
import java.util.Map;
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;
import net.runelite.api.NpcID;
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.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
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",
description = "Tick timers for bosses",
tags = {"pvm", "bossing"},
enabledByDefault = false,
type = PluginType.PVM
)
@Slf4j
public class TickTimersPlugin extends Plugin
{
private static final int GENERAL_REGION = 11347;
@Inject
private Client client;
@Inject
private OverlayManager overlayManager;
@Inject
private TimersOverlay timersOverlay;
@Inject
private TickTimersConfig config;
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Strongstack = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Steelwill = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Grimspike = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> General = new HashMap<>();
@Provides
TickTimersConfig getConfig(ConfigManager configManager)
{
return configManager.getConfig(TickTimersConfig.class);
}
@Override
public void startUp()
{
Strongstack.clear();
Steelwill.clear();
Grimspike.clear();
General.clear();
}
@Override
public void shutDown()
{
Strongstack.clear();
Steelwill.clear();
Grimspike.clear();
General.clear();
}
@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;
}
Strongstack.clear();
Steelwill.clear();
Grimspike.clear();
General.clear();
}
@Subscribe
public void onNpcSpawned(NpcSpawned event)
{
NPC npc = event.getNpc();
switch (npc.getId())
{
case NpcID.SERGEANT_STRONGSTACK:
Strongstack.put(npc, new NPCContainer(npc));
break;
case NpcID.SERGEANT_STEELWILL:
Steelwill.put(npc, new NPCContainer(npc));
break;
case NpcID.SERGEANT_GRIMSPIKE:
Grimspike.put(npc, new NPCContainer(npc));
break;
case NpcID.GENERAL_GRAARDOR:
case NpcID.GENERAL_GRAARDOR_6494:
General.put(npc, new NPCContainer(npc));
break;
}
}
@Subscribe
public void onNpcDespawned(NpcDespawned event)
{
if (Grimspike.remove(event.getNpc()) != null && !Grimspike.isEmpty())
{
Grimspike.clear();
}
if (Steelwill.remove(event.getNpc()) != null && !Steelwill.isEmpty())
{
Steelwill.clear();
}
if (Strongstack.remove(event.getNpc()) != null && !Strongstack.isEmpty())
{
Strongstack.clear();
}
if (General.remove(event.getNpc()) != null && !General.isEmpty())
{
General.clear();
}
}
@Subscribe
public void onGameTick(GameTick Event)
{
if (config.graardor())
{
graardorHandler();
}
}
private void graardorHandler()
{
for (NPCContainer grimspike : getGrimspike().values())
{
grimspike.setTicksUntilAttack(grimspike.getTicksUntilAttack() - 1);
switch (grimspike.getNpc().getAnimation())
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
case AnimationID.MINION_AUTO4:
if (grimspike.getTicksUntilAttack() < 1)
{
grimspike.setTicksUntilAttack(5);
}
break;
}
}
for (NPCContainer strongstack : getStrongstack().values())
{
strongstack.setTicksUntilAttack(strongstack.getTicksUntilAttack() - 1);
switch (strongstack.getNpc().getAnimation())
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
if (strongstack.getTicksUntilAttack() < 1)
{
strongstack.setTicksUntilAttack(5);
}
break;
}
}
for (NPCContainer steelwill : getSteelwill().values())
{
steelwill.setTicksUntilAttack(steelwill.getTicksUntilAttack() - 1);
switch (steelwill.getNpc().getAnimation())
{
case AnimationID.MINION_AUTO1:
case AnimationID.MINION_AUTO2:
case AnimationID.MINION_AUTO3:
if (steelwill.getTicksUntilAttack() < 1)
{
steelwill.setTicksUntilAttack(5);
}
break;
}
}
for (NPCContainer boss : getGeneral().values())
{
boss.setTicksUntilAttack(boss.getTicksUntilAttack() - 1);
switch (boss.getNpc().getAnimation())
{
case AnimationID.GENERAL_AUTO1:
case AnimationID.GENERAL_AUTO2:
case AnimationID.GENERAL_AUTO3:
if (boss.getTicksUntilAttack() < 1)
{
boss.setTicksUntilAttack(6);
}
break;
}
}
}
private boolean isInGeneralRegion()
{
return ArrayUtils.contains(client.getMapRegions(), GENERAL_REGION);
}
}

View File

@@ -0,0 +1,193 @@
/*
* 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.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Polygon;
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.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;
public class TimersOverlay extends Overlay
{
private TickTimersPlugin plugin;
private Client client;
private TickTimersConfig config;
@Inject
TimersOverlay(TickTimersPlugin plugin, Client client, TickTimersConfig config)
{
this.plugin = plugin;
this.client = client;
this.config = config;
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
}
@Override
public Dimension render(Graphics2D graphics)
{
Color tickcolor;
for (NPCContainer npc : plugin.getStrongstack().values())
{
renderNpcOverlay(graphics, npc.getNpc(), Color.RED, 100, 10);
final int ticksLeft = npc.getTicksUntilAttack();
if (ticksLeft > 0)
{
if (ticksLeft == 1)
{
tickcolor = Color.RED;
}
else
{
tickcolor = Color.WHITE;
}
final String ticksLeftStr = String.valueOf(ticksLeft);
Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0);
renderTextLocation(graphics, ticksLeftStr, config.textSize(), config.fontStyle().getFont(), tickcolor, canvasPoint);
}
}
for (NPCContainer npc : plugin.getSteelwill().values())
{
renderNpcOverlay(graphics, npc.getNpc(), Color.CYAN, 100, 10);
final int ticksLeft = npc.getTicksUntilAttack();
if (ticksLeft > 0)
{
if (ticksLeft == 1)
{
tickcolor = Color.CYAN;
}
else
{
tickcolor = Color.WHITE;
}
final String ticksLeftStr = String.valueOf(ticksLeft);
Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0);
renderTextLocation(graphics, ticksLeftStr, config.textSize(), config.fontStyle().getFont(), tickcolor, canvasPoint);
}
}
for (NPCContainer npc : plugin.getGrimspike().values())
{
renderNpcOverlay(graphics, npc.getNpc(), Color.GREEN, 100, 10);
final int ticksLeft = npc.getTicksUntilAttack();
if (ticksLeft > 0)
{
if (ticksLeft == 1)
{
tickcolor = Color.GREEN;
}
else
{
tickcolor = Color.WHITE;
}
final String ticksLeftStr = String.valueOf(ticksLeft);
Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0);
renderTextLocation(graphics, ticksLeftStr, config.textSize(), config.fontStyle().getFont(), tickcolor, canvasPoint);
}
}
for (NPCContainer npc : plugin.getGeneral().values())
{
renderNpcOverlay(graphics, npc.getNpc(), Color.RED, 100, 10);
final int ticksLeft = npc.getTicksUntilAttack();
if (ticksLeft > 0)
{
if (ticksLeft == 1)
{
tickcolor = Color.RED;
}
else
{
tickcolor = Color.WHITE;
}
final String ticksLeftStr = String.valueOf(ticksLeft);
Point canvasPoint = npc.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)
{
graphics.setFont(new Font("Arial", fontStyle, fontSize));
if (canvasPoint != null)
{
final Point canvasCenterPoint = new Point(
canvasPoint.getX(),
canvasPoint.getY());
final Point canvasCenterPoint_shadow = new Point(
canvasPoint.getX() + 1,
canvasPoint.getY() + 1);
if (config.shadows())
{
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK);
}
OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor);
}
}
}