diff --git a/runelite-api/src/main/java/net/runelite/api/AnimationID.java b/runelite-api/src/main/java/net/runelite/api/AnimationID.java index 39353a15f4..3cc792aae9 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -173,7 +173,7 @@ public final class AnimationID public static final int VORKATH_DEATH = 7949; public static final int VORKATH_SLASH_ATTACK = 7951; public static final int VORKATH_ATTACK = 7952; - public static final int VORKATH_FIRE_BOMB_ATTACK = 7960; + public static final int VORKATH_FIRE_BOMB_OR_SPAWN_ATTACK = 7960; public static final int VORKATH_ACID_ATTACK = 7957; public static final int BLACKJACK_KO = 838; public static final int VETION_EARTHQUAKE = 5507; diff --git a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java index 5dff0bc450..aa714128ea 100644 --- a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java +++ b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java @@ -93,7 +93,7 @@ public class ProjectileID public static final int VORKATH_MAGIC = 1479; public static final int VORKATH_PRAYER_DISABLE = 1471; public static final int VORKATH_VENOM = 1470; - public static final int VORKATH_ICE = 350; + public static final int VORKATH_ICE = 395; public static final int HYDRA_MAGIC = 1662; public static final int HYDRA_RANGED = 1663; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/Vorkath.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/Vorkath.java index 8eff3a892c..f6148a3b0d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/Vorkath.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/Vorkath.java @@ -24,45 +24,84 @@ */ package net.runelite.client.plugins.vorkath; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.NPC; +@Data +@Slf4j public class Vorkath { static final int ATTACKS_PER_SWITCH = 6; + static final int FIRE_BALL_ATTACKS = 25; - enum AttackStyle + private NPC vorkath; + + private VorkathAttack lastAttack; + + private Phase currentPhase; + private Phase nextPhase; + private Phase lastPhase; + + private int attacksLeft; + + enum Phase { - MAGERANGE, - ICE, + UNKNOWN, ACID, - SPECIAL + FIRE_BALL, + SPAWN } - @Getter - private NPC npc; - - @Getter - @Setter - private int phase; - - @Getter - @Setter - private int attacksUntilSwitch; - - @Getter - @Setter - private int lastTickAnimation; - - @Getter - @Setter - private boolean icePhaseAttack; - - public Vorkath(NPC npc) + public Vorkath(NPC vorkath) { - this.npc = npc; - this.attacksUntilSwitch = ATTACKS_PER_SWITCH; - this.phase = 0; + this.vorkath = vorkath; + this.attacksLeft = ATTACKS_PER_SWITCH; + this.currentPhase = Phase.UNKNOWN; + this.nextPhase = Phase.UNKNOWN; + this.lastPhase = Phase.UNKNOWN; + log.debug("[Vorkath] Created Vorkath: {}", this); + } + + /** + * Updates the existing Vorkath object depending on the new phase it is currently on + * @param newPhase the new phase Vorkath is current on + */ + public void updatePhase(Phase newPhase) + { + Phase oldLastPhase = this.lastPhase; + Phase oldCurrentPhase = this.currentPhase; + Phase oldNextPhase = this.currentPhase; + int oldAttacksLeft = this.attacksLeft; + + this.lastPhase = this.currentPhase; + this.currentPhase = newPhase; + switch (newPhase) + { + case ACID: + this.nextPhase = Phase.FIRE_BALL; + break; + case FIRE_BALL: + this.nextPhase = Phase.SPAWN; + break; + case SPAWN: + this.nextPhase = Phase.ACID; + break; + default: + this.nextPhase = Phase.UNKNOWN; + break; + } + + if (this.currentPhase == Phase.FIRE_BALL) + { + this.attacksLeft = FIRE_BALL_ATTACKS; + } + else + { + this.attacksLeft = ATTACKS_PER_SWITCH; + } + + log.debug("[Vorkath] Update! Last Phase: {}->{}, Current Phase: {}->{}, Next Phase: {}->{}, Attacks: {}->{}", + oldLastPhase, this.lastPhase, oldCurrentPhase, this.currentPhase, oldNextPhase, this.nextPhase, oldAttacksLeft, this.attacksLeft); } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathAttack.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathAttack.java new file mode 100644 index 0000000000..edb86434be --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathAttack.java @@ -0,0 +1,108 @@ +package net.runelite.client.plugins.vorkath; + +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.AnimationID; +import net.runelite.api.ProjectileID; + +@AllArgsConstructor +@Getter +public enum VorkathAttack +{ + /** + * Vorkath's melee attack (see VorkathPlugin#onAnimationChanged) + */ + SLASH_ATTACK(AnimationID.VORKATH_SLASH_ATTACK, -1), + /** + * Vorkath's dragon breath attack + */ + FIRE_BREATH(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_DRAGONBREATH), + /** + * Vorkath's dragon breath attack causing the player's active prayers to be deactivated + */ + PRAYER_BREATH(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_PRAYER_DISABLE), + /** + * Vorkath's dragon breath attack causing the player to become poisoned with venom + */ + VENOM_BREATH(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_VENOM), + /** + * Vorkath's ranged attack + */ + SPIKE(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_RANGED), + /** + * Vorkath's magic attack + */ + ICE(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_MAGIC), + /** + * Vorkath's aoe fire bomb attack (3x3 from where player was originally standing) + */ + FIRE_BOMB(AnimationID.VORKATH_FIRE_BOMB_OR_SPAWN_ATTACK, ProjectileID.VORKATH_BOMB_AOE), + /** + * Vorkath's aoe acid attacking, spewing acid across the instance + */ + ACID(AnimationID.VORKATH_ACID_ATTACK, ProjectileID.VORKATH_POISON_POOL_AOE), + /** + * Vorkath's fire ball attack that is fired during the acid phase, almost every tick for 25(?) attacks total + */ + FIRE_BALL(AnimationID.VORKATH_ACID_ATTACK, ProjectileID.VORKATH_TICK_FIRE_AOE), + /** + * Vorkath's dragon breath attack causing the player to be frozen during Zombified Spawn phase + */ + FREEZE_BREATH(AnimationID.VORKATH_ATTACK, ProjectileID.VORKATH_ICE), + /** + * Vorkath's spawning of a Zombified Spawn + */ + ZOMBIFIED_SPAWN(AnimationID.VORKATH_FIRE_BOMB_OR_SPAWN_ATTACK, ProjectileID.VORKATH_SPAWN_AOE); + + private final int vorkathAnimationID; + private final int projectileID; + + private static final Map VORKATH_ATTACKS; + private static final Map VORKATH_BASIC_ATTACKS; + + static + { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + for (VorkathAttack vorkathAttack : values()) + { + builder.put(vorkathAttack.getProjectileID(), vorkathAttack); + } + VORKATH_ATTACKS = builder.build(); + } + + static + { + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + builder.put(FIRE_BREATH.getProjectileID(), FIRE_BREATH) + .put(PRAYER_BREATH.getProjectileID(), PRAYER_BREATH) + .put(VENOM_BREATH.getProjectileID(), VENOM_BREATH) + .put(SPIKE.getProjectileID(), SPIKE) + .put(ICE.getProjectileID(), ICE) + .put(FIRE_BOMB.getProjectileID(), FIRE_BOMB) + .put(FIRE_BALL.getProjectileID(), FIRE_BALL); + // FIRE_BOMB and FIRE_BALL are also basic attacks + // Although SLASH_ATTACK is a basic attack, we're going to handle it differently + VORKATH_BASIC_ATTACKS = builder.build(); + } + + /** + * @param projectileID id of projectile + * @return {@link VorkathAttack} associated with the specified projectile + */ + public static VorkathAttack getVorkathAttack(int projectileID) + { + return VORKATH_ATTACKS.get(projectileID); + } + + /** + * @param projectileID + * @return true if the projectile id matches a {@link VorkathAttack#getProjectileID()} within {@link VorkathAttack#VORKATH_BASIC_ATTACKS}, + * false otherwise + */ + public static boolean isBasicAttack(int projectileID) + { + return VORKATH_BASIC_ATTACKS.get(projectileID) != null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathConfig.java new file mode 100644 index 0000000000..2368cb8c9a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathConfig.java @@ -0,0 +1,22 @@ +package net.runelite.client.plugins.vorkath; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +/** + * Created on 6/4/2019. + */ +@ConfigGroup("vorkath") +public interface VorkathConfig extends Config +{ + @ConfigItem( + keyName = "fireBombNotification", + name = "Fire Bomb Notification", + description = "Sends a system notification when Vorkath attack with his fire bomb" + ) + default boolean shouldNotifyOnFireBomb() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathOverlay.java index c29b561146..c3d18e7450 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathOverlay.java @@ -59,20 +59,6 @@ public class VorkathOverlay extends Overlay this.plugin = plugin; } - private BufferedImage getIcon(Vorkath.AttackStyle attackStyle) - { - switch (attackStyle) - { - case MAGERANGE: - return VorkathPlugin.MAGERANGE; - case ICE: - return VorkathPlugin.ICE; - case ACID: - return VorkathPlugin.ACID; - } - return null; - } - @Override public Dimension render(Graphics2D graphics) { @@ -80,29 +66,17 @@ public class VorkathOverlay extends Overlay { Vorkath vorkath = plugin.getVorkath(); - LocalPoint localLocation = vorkath.getNpc().getLocalLocation(); + LocalPoint localLocation = vorkath.getVorkath().getLocalLocation(); if (localLocation != null) { - Point point = Perspective.localToCanvas(client, localLocation, client.getPlane(), vorkath.getNpc().getLogicalHeight() + 16); + Point point = Perspective.localToCanvas(client, localLocation, client.getPlane(), vorkath.getVorkath().getLogicalHeight() + 16); if (point != null) { point = new Point(point.getX(), point.getY()); - BufferedImage icon = null; - if (vorkath.getPhase() == 0) - { - icon = getIcon(Vorkath.AttackStyle.MAGERANGE); - } - else if (vorkath.getPhase() == 1) - { - icon = getIcon(Vorkath.AttackStyle.ACID); - } - else if (vorkath.getPhase() == 2) - { - icon = getIcon(Vorkath.AttackStyle.ICE); - } + BufferedImage currentPhaseIcon = getIcon(vorkath); - int totalWidth = icon.getWidth() * OVERLAY_ICON_MARGIN; + int totalWidth = currentPhaseIcon.getWidth() * OVERLAY_ICON_MARGIN; int bgPadding = 8; int currentPosX = 0; @@ -110,32 +84,31 @@ public class VorkathOverlay extends Overlay graphics.setColor(COLOR_ICON_BACKGROUND); graphics.fillOval( point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2); + point.getY() - currentPhaseIcon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + currentPhaseIcon.getWidth() + bgPadding * 2, + currentPhaseIcon.getHeight() + bgPadding * 2); graphics.setColor(COLOR_ICON_BORDER); graphics.drawOval( point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2); + point.getY() - currentPhaseIcon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + currentPhaseIcon.getWidth() + bgPadding * 2, + currentPhaseIcon.getHeight() + bgPadding * 2); graphics.drawImage( - icon, + currentPhaseIcon, point.getX() - totalWidth / 2 + currentPosX, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE, + point.getY() - currentPhaseIcon.getHeight() / 2 - OVERLAY_ICON_DISTANCE, null); graphics.setColor(COLOR_ICON_BORDER_FILL); Arc2D.Double arc = new Arc2D.Double( point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2, + point.getY() - currentPhaseIcon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + currentPhaseIcon.getWidth() + bgPadding * 2, + currentPhaseIcon.getHeight() + bgPadding * 2, 90.0, - -360.0 * (Vorkath.ATTACKS_PER_SWITCH - - vorkath.getAttacksUntilSwitch()) / Vorkath.ATTACKS_PER_SWITCH, + -360.0 * getAttacksLeftProgress(), Arc2D.OPEN); graphics.draw(arc); } @@ -144,4 +117,39 @@ public class VorkathOverlay extends Overlay return null; } + + /** + * @param vorkath Vorkath object + * @return image of the current phase Vorkath is on + */ + private BufferedImage getIcon(Vorkath vorkath) + { + switch (vorkath.getCurrentPhase()) + { + case UNKNOWN: + return VorkathPlugin.UNKNOWN; + case ACID: + return VorkathPlugin.ACID; + case FIRE_BALL: + return VorkathPlugin.FIRE_BALL; + case SPAWN: + return VorkathPlugin.SPAWN; + } + return null; + } + + /** + * @return number of attacks Vorkath has left in the current phase + */ + private double getAttacksLeftProgress() + { + if (plugin.getVorkath().getCurrentPhase() != Vorkath.Phase.FIRE_BALL) + { + return (double) (Vorkath.ATTACKS_PER_SWITCH - plugin.getVorkath().getAttacksLeft()) / Vorkath.ATTACKS_PER_SWITCH; + } + else + { + return (double) (Vorkath.FIRE_BALL_ATTACKS - plugin.getVorkath().getAttacksLeft()) / Vorkath.FIRE_BALL_ATTACKS; + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathPlugin.java index 49eccd4fde..184d004add 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/VorkathPlugin.java @@ -24,25 +24,28 @@ */ package net.runelite.client.plugins.vorkath; +import com.google.inject.Inject; +import com.google.inject.Provides; +import java.awt.TrayIcon; import java.awt.image.BufferedImage; -import javax.inject.Inject; import lombok.Getter; -import net.runelite.api.AnimationID; +import lombok.extern.slf4j.Slf4j; 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.AnimationChanged; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; -import net.runelite.client.callback.ClientThread; +import net.runelite.api.events.ProjectileMoved; +import net.runelite.client.Notifier; +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 net.runelite.client.util.ImageUtil; +import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Vorkath Helper", @@ -51,12 +54,20 @@ import net.runelite.client.util.ImageUtil; type = PluginType.PVM, enabledByDefault = false ) - +@Slf4j public class VorkathPlugin extends Plugin { + private static final int VORKATH_REGION = 9023; + @Inject private Client client; + @Inject + private VorkathConfig config; + + @Inject + private Notifier notifier; + @Inject private OverlayManager overlayManager; @@ -66,24 +77,28 @@ public class VorkathPlugin extends Plugin @Inject private ZombifiedSpawnOverlay SpawnOverlay; - @Inject - private ClientThread clientThread; - @Getter private Vorkath vorkath; @Getter - private ZombifiedSpawn spawn; + private NPC zombifiedSpawn; + /** + * The last projectile's starting movement cycle + */ + private int lastProjectileCycle; + + static final BufferedImage UNKNOWN; static final BufferedImage ACID; - static final BufferedImage ICE; - static final BufferedImage MAGERANGE; + static final BufferedImage FIRE_BALL; + static final BufferedImage SPAWN; static { + UNKNOWN = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "magerange.png"); ACID = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "acid.png"); - ICE = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "ice.png"); - MAGERANGE = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "magerange.png"); + FIRE_BALL = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "fire_strike.png"); + SPAWN = ImageUtil.getResourceStreamFromClass(VorkathPlugin.class, "ice.png"); } @Override @@ -91,7 +106,12 @@ public class VorkathPlugin extends Plugin { overlayManager.add(overlay); overlayManager.add(SpawnOverlay); - clientThread.invoke(this::reset); + } + + @Provides + VorkathConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(VorkathConfig.class); } @Override @@ -101,121 +121,153 @@ public class VorkathPlugin extends Plugin overlayManager.remove(SpawnOverlay); } - private void reset() - { - this.vorkath = null; - for (NPC npc : client.getNpcs()) - { - if (isNpcVorkath(npc.getId())) - { - this.vorkath = new Vorkath(npc); - } - else if (isNpcZombifiedSpawn(npc.getId())) - { - this.spawn = new ZombifiedSpawn(npc); - } - } - } - - private static boolean isNpcVorkath(int npcId) - { - return npcId == NpcID.VORKATH || - npcId == NpcID.VORKATH_8058 || - npcId == NpcID.VORKATH_8059 || - npcId == NpcID.VORKATH_8060 || - npcId == NpcID.VORKATH_8061; - } - - private static boolean isNpcZombifiedSpawn(int id) - { - return id == NpcID.ZOMBIFIED_SPAWN || - id == NpcID.ZOMBIFIED_SPAWN_8063; - } - @Subscribe public void onNpcSpawned(NpcSpawned event) { - NPC npc = event.getNpc(); - if (isNpcVorkath(npc.getId())) + if (isAtVorkath()) { - this.vorkath = new Vorkath(npc); - } - else if (isNpcZombifiedSpawn(npc.getId())) - { - this.spawn = new ZombifiedSpawn(npc); - } - } - - @Subscribe - public void onNpcDespawned(NpcDespawned npcDespawned) - { - final NPC npc = npcDespawned.getNpc(); - if (this.vorkath != null) - { - if (npc.getId() == this.vorkath.getNpc().getId()) + if (isVorkath(event.getNpc().getId())) { - this.vorkath = null; - reset(); + vorkath = new Vorkath(event.getNpc()); + lastProjectileCycle = -1; } - } - - if (this.spawn != null) - { - if (npc.getId() == this.spawn.getNpc().getId()) + else if (isZombifiedSpawn(event.getNpc().getId())) { - this.spawn = null; + zombifiedSpawn = event.getNpc(); } } } - @Subscribe - public void onGameStateChanged(GameStateChanged event) + public void onNpcDespawned(NpcDespawned event) { - GameState gs = event.getGameState(); - if (gs == GameState.LOGGING_IN || - gs == GameState.CONNECTION_LOST || - gs == GameState.HOPPING) + if (isAtVorkath()) { - reset(); + if (isVorkath(event.getNpc().getId())) + { + vorkath = null; + lastProjectileCycle = -1; + } + else if (isZombifiedSpawn(event.getNpc().getId())) + { + zombifiedSpawn = null; + } } } @Subscribe - public void onGameTick(GameTick event) + public void onProjectileMoved(ProjectileMoved event) { - if (vorkath != null) + // Only capture initial projectile + if (!isAtVorkath() || event.getProjectile().getStartMovementCycle() == lastProjectileCycle) { - int animationId = vorkath.getNpc().getAnimation(); + return; + } - if (animationId != vorkath.getLastTickAnimation()) + VorkathAttack vorkathAttack = VorkathAttack.getVorkathAttack(event.getProjectile().getId()); + if (vorkathAttack != null) + { + /*log.debug("[Projectile ({})] Game Tick: {}, Game Cycle: {}, Starting Cyle: {} Last Cycle: {}, Initial Projectile?: {}", + vorkathAttack, client.getTickCount(), client.getGameCycle(), event.getProjectile().getStartMovementCycle(), + lastProjectileCycle, event.getProjectile().getStartMovementCycle() == client.getGameCycle());*/ + if (VorkathAttack.isBasicAttack(vorkathAttack.getProjectileID()) && vorkath.getAttacksLeft() > 0) { - if (animationId == AnimationID.VORKATH_ACID_ATTACK) + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - 1); + if (config.shouldNotifyOnFireBomb() && vorkathAttack == VorkathAttack.FIRE_BOMB) { - vorkath.setPhase(2); - vorkath.setAttacksUntilSwitch(Vorkath.ATTACKS_PER_SWITCH); - } - else if (animationId == AnimationID.VORKATH_ATTACK && vorkath.getAttacksUntilSwitch() == 0) - { - vorkath.setPhase(1); - vorkath.setAttacksUntilSwitch(Vorkath.ATTACKS_PER_SWITCH); - //Vorkath does a bomb animation after the ice dragon breathe, we need to account for it - vorkath.setIcePhaseAttack(true); - } - else if (animationId == AnimationID.VORKATH_ATTACK || animationId == AnimationID.VORKATH_FIRE_BOMB_ATTACK) - { - if (vorkath.isIcePhaseAttack()) - { - vorkath.setIcePhaseAttack(false); - } - else - { - vorkath.setAttacksUntilSwitch(vorkath.getAttacksUntilSwitch() - 1); - } + notifier.notify("Vorkath used it's fire bomb attack!", TrayIcon.MessageType.WARNING); } } + else if (vorkathAttack == VorkathAttack.ACID) + { + vorkath.updatePhase(Vorkath.Phase.ACID); + // Sets the phase's progress indicator to done + vorkath.setAttacksLeft(0); + } + else if (vorkathAttack == VorkathAttack.FIRE_BALL) + { + vorkath.updatePhase(Vorkath.Phase.FIRE_BALL); + // Decrement to account for this fire ball + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - 1); + } + else if (vorkathAttack == VorkathAttack.FREEZE_BREATH && vorkath.getLastAttack() != VorkathAttack.ZOMBIFIED_SPAWN) + { + // Filters out second invisible freeze attack that is immediately after the Zombified Spawn + vorkath.updatePhase(Vorkath.Phase.SPAWN); + // Sets progress of the phase to half + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - (vorkath.getAttacksLeft() / 2)); + } + else if (vorkathAttack == VorkathAttack.ZOMBIFIED_SPAWN || (vorkath.getLastAttack() == VorkathAttack.ZOMBIFIED_SPAWN)) + { + // Also consumes the second invisible freeze attack that is immediately after the Zombified Spawn + // Sets progress of the phase to done as there are no more attacks within this phase + vorkath.setAttacksLeft(0); + } + else + { + // Vorkath fired a basic attack AND there are no more attacks left, typically after phases are over + vorkath.updatePhase(vorkath.getNextPhase()); + // Decrement to account for this basic attack + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - 1); + } - vorkath.setLastTickAnimation(animationId); + log.debug("[Vorkath ({})] {}", vorkathAttack, vorkath); + vorkath.setLastAttack(vorkathAttack); + lastProjectileCycle = event.getProjectile().getStartMovementCycle(); } } + + @Subscribe + public void onAnimationChanged(AnimationChanged event) + { + if (isAtVorkath() && vorkath != null && event.getActor().equals(vorkath.getVorkath()) + && event.getActor().getAnimation() == VorkathAttack.SLASH_ATTACK.getVorkathAnimationID()) + { + if (vorkath.getAttacksLeft() > 0) + { + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - 1); + } + else + { + // No more attacks left, typically after phases are over + vorkath.updatePhase(vorkath.getNextPhase()); + // Decrement to account for this basic attack + vorkath.setAttacksLeft(vorkath.getAttacksLeft() - 1); + } + log.debug("[Vorkath (SLASH_ATTACK)] {}", vorkath); + } + } + + /** + * @return true if the player is in the Vorkath region, false otherwise + */ + private boolean isAtVorkath() + { + return ArrayUtils.contains(client.getMapRegions(), VORKATH_REGION); + } + + /** + * @param npcID + * @return true if the npc is Vorkath, false otherwise + */ + private boolean isVorkath(int npcID) + { + // Could be done with a a simple name check instead... + return npcID == NpcID.VORKATH || + npcID == NpcID.VORKATH_8058 || + npcID == NpcID.VORKATH_8059 || + npcID == NpcID.VORKATH_8060 || + npcID == NpcID.VORKATH_8061; + } + + /** + * @param npcID + * @return true if the npc is a Zombified Spawn, otherwise false + */ + private boolean isZombifiedSpawn(int npcID) + { + // Could be done with a a simple name check instead... + return npcID == NpcID.ZOMBIFIED_SPAWN || + npcID == NpcID.ZOMBIFIED_SPAWN_8063; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawn.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawn.java deleted file mode 100644 index 8d38c26926..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawn.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.vorkath; - -import lombok.Getter; -import net.runelite.api.NPC; - -class ZombifiedSpawn -{ - @Getter - private NPC npc; - - ZombifiedSpawn(NPC npc) - { - this.npc = npc; - } -} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawnOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawnOverlay.java index 28bd682d2f..50fb185532 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawnOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vorkath/ZombifiedSpawnOverlay.java @@ -48,10 +48,9 @@ public class ZombifiedSpawnOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (plugin.getSpawn() != null) + if (plugin.getZombifiedSpawn() != null) { - ZombifiedSpawn spawn = plugin.getSpawn(); - OverlayUtil.renderActorOverlayImage(graphics, spawn.getNpc(), VorkathPlugin.ICE, Color.green, 10); + OverlayUtil.renderActorOverlayImage(graphics, plugin.getZombifiedSpawn(), VorkathPlugin.SPAWN, Color.green, 10); } return null; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/vorkath/fire_strike.png b/runelite-client/src/main/resources/net/runelite/client/plugins/vorkath/fire_strike.png new file mode 100644 index 0000000000..eec1fd6bec Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/vorkath/fire_strike.png differ