From 666e3cf4df06ab9af80a0bc3d498f92c9927deb7 Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Thu, 16 Apr 2026 00:41:00 +0100 Subject: [PATCH 1/2] WIP --- .../java/com/attacktimer/AnimationData.java | 2 +- .../java/com/attacktimer/AttackStyle.java | 6 + .../AttackTimerMetronomePlugin.java | 111 ++++++++- .../com/attacktimer/ClientUtils/Utils.java | 62 ++++- .../VariableSpeed/BloodMoonSet.java | 6 +- .../attacktimer/VariableSpeed/EyeOfAyak.java | 5 +- .../VariableSpeed/IVariableSpeed.java | 11 +- .../VariableSpeed/Leagues4and5.java | 6 +- .../VariableSpeed/PurgingStaffSpec.java | 230 ++++++++++++++++++ .../VariableSpeed/RapidAttackStyle.java | 7 +- .../VariableSpeed/RedKerisSpec.java | 4 +- .../attacktimer/VariableSpeed/Scurrius.java | 4 +- .../VariableSpeed/TombsOfAmascut.java | 4 +- .../VariableSpeed/TormentedDemons.java | 4 +- .../VariableSpeed/VariableSpeed.java | 19 +- 15 files changed, 433 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java diff --git a/src/main/java/com/attacktimer/AnimationData.java b/src/main/java/com/attacktimer/AnimationData.java index 3fad116..c1788e9 100644 --- a/src/main/java/com/attacktimer/AnimationData.java +++ b/src/main/java/com/attacktimer/AnimationData.java @@ -187,7 +187,7 @@ public enum AnimationData MAGIC_ANCIENT_MULTI_TARGET_PVP(1979, AttackStyle.MAGIC, Spellbook.ANCIENT), // Burst & Barrage animations (tested all 8, different weapons) MAGIC_ANCIENT_SINGLE_TARGET(10091, AttackStyle.MAGIC, Spellbook.ANCIENT), // Rush & Blitz animations (tested all 8, different weapons) MAGIC_ANCIENT_SINGLE_TARGET_PVP(1978, AttackStyle.MAGIC, Spellbook.ANCIENT), // Rush & Blitz animations - + MAGIC_ARCEUUS_DEMONBANE(8977, AttackStyle.MAGIC, Spellbook.ARCEUUS), // Also greater corruption, so that may accidentally trigger a manual-cast, but that's probably fine only affects Muspah MAGIC_ARCEUUS_GRASP(8972, AttackStyle.MAGIC, Spellbook.ARCEUUS), diff --git a/src/main/java/com/attacktimer/AttackStyle.java b/src/main/java/com/attacktimer/AttackStyle.java index 1da0c19..e6b2b9f 100644 --- a/src/main/java/com/attacktimer/AttackStyle.java +++ b/src/main/java/com/attacktimer/AttackStyle.java @@ -51,4 +51,10 @@ public enum AttackStyle this.name = name; this.skills = skills; } + + @Override + public String toString() + { + return this.name; + } } \ No newline at end of file diff --git a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java index 8428378..8d8ce50 100644 --- a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java +++ b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java @@ -1,5 +1,6 @@ package com.attacktimer; +import com.attacktimer.ClientUtils.Utils; /* * Copyright (c) 2022, Nick Graves @@ -29,6 +30,7 @@ */ import com.attacktimer.VariableSpeed.VariableSpeed; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.io.ByteArrayDataOutput; @@ -36,6 +38,7 @@ import java.awt.Color; import java.awt.Dimension; import java.nio.charset.StandardCharsets; +import java.util.ArrayDeque; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -45,18 +48,24 @@ import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.InventoryID; +import net.runelite.api.GameState; import net.runelite.api.Item; import net.runelite.api.ItemContainer; import net.runelite.api.NPC; import net.runelite.api.Player; +import net.runelite.api.Skill; import net.runelite.api.Varbits; import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.FakeXpDrop; import net.runelite.api.events.GameTick; import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.SoundEffectPlayed; +import net.runelite.api.events.StatChanged; import net.runelite.api.events.VarClientIntChanged; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.gameval.InventoryID; +import net.runelite.api.gameval.VarPlayerID; +import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; @@ -106,6 +115,9 @@ public enum AttackState @Inject private NPCManager npcManager; + @Inject + private ClientThread clientThread; + public int tickPeriod = 0; private int uiHideDebounceTickCount = 0; @@ -126,6 +138,14 @@ public enum AttackState public int pendingEatDelayTicks = 0; + private ArrayDeque specialPercentageEvents = new ArrayDeque(); + private Map> combatExpEarned = Map.of( + Skill.MAGIC, new ArrayDeque(), + Skill.RANGED, new ArrayDeque(), + Skill.DEFENCE, new ArrayDeque(), + Skill.STRENGTH, new ArrayDeque(), + Skill.ATTACK, new ArrayDeque() + ); private static final int UI_HIDE_DEBOUNCE_TICKS_MAX = 1; private static final int ATTACK_DELAY_NONE = 0; @@ -188,6 +208,10 @@ public void onVarbitChanged(VarbitChanged varbitChanged) { currentSpellBook = Spellbook.fromVarbit(varbitChanged.getValue()); } + if (varbitChanged.getVarpId() == VarPlayerID.SA_ENERGY) + { + specialPercentageEvents.addLast(varbitChanged.getValue()); + } } // onVarbitChanged happens when the user causes some interaction therefore we can't rely on some fixed @@ -227,6 +251,34 @@ public void onSoundEffectPlayed(SoundEffectPlayed event) soundEffectId = event.getSoundId(); } + @Subscribe + protected void onFakeXpDrop(FakeXpDrop event) + { + if (!combatExpEarned.containsKey(event.getSkill())) + { + return; + } + combatExpEarned.get(event.getSkill()).addLast(event.getXp()); + if (attackState == AttackState.DELAYED_FIRST_TICK) + { + performAttack(); + } + } + + @Subscribe + protected void onStatChanged(StatChanged event) + { + if (!combatExpEarned.containsKey(event.getSkill())) + { + return; + } + combatExpEarned.get(event.getSkill()).addLast(event.getXp()); + if (attackState == AttackState.DELAYED_FIRST_TICK) + { + performAttack(); + } + } + // endregion @Provides @@ -235,6 +287,35 @@ AttackTimerMetronomeConfig provideConfig(ConfigManager configManager) return configManager.getConfig(AttackTimerMetronomeConfig.class); } + private int computeDamage(AttackStyle attackStyle, AttackProcedure atkType, AnimationData curAnimation) + { + switch (atkType) { + case POWERED_STAVE: + // TODO not needed for any variable speed + return -1; + case MANUAL_AUTO_CAST: + if (attackStyle == AttackStyle.DEFENSIVE_CASTING || attackStyle == AttackStyle.DEFENSIVE) { + // just use the defense exp to compute the damage + System.out.println("computeDamage (DEFENCE): " + Utils.getLastDelta(combatExpEarned.get(Skill.DEFENCE)) + " | " + combatExpEarned.get(Skill.DEFENCE)); + return Utils.getLastDelta(combatExpEarned.get(Skill.DEFENCE)); + } else { + // deduct the fixed exp based on the spell + // (for now this only works for dark demon bane which awkwardly gives fractional exp) + var mageExp = Utils.getLastDelta(combatExpEarned.get(Skill.MAGIC)); + if (curAnimation != AnimationData.MAGIC_ARCEUUS_DEMONBANE) + { + return -1; + } + System.out.println("computeDamage (MAGIC): " + Utils.getLastDelta(combatExpEarned.get(Skill.MAGIC)) + " | " + combatExpEarned.get(Skill.MAGIC)); + return (int) Math.ceil(((double) mageExp - 43.5D) / 2.0D); + } + case MELEE_OR_RANGE: + // TODO not needed for any variable speed + return -1; + } + return -1; + } + private int getItemIdFromContainer(ItemContainer container, int slotID) { if (container == null) @@ -248,7 +329,7 @@ private int getItemIdFromContainer(ItemContainer container, int slotID) private int getWeaponId() { int weaponId = getItemIdFromContainer( - client.getItemContainer(InventoryID.EQUIPMENT), + client.getItemContainer(InventoryID.WORN), EquipmentInventorySlot.WEAPON.getSlotIdx() ); @@ -302,27 +383,32 @@ private int getMagicBaseSpeed(int weaponId) private int getWeaponSpeed(int weaponId, PoweredStaves stave, AnimationData curAnimation, boolean matchesSpellbook) { + var specDelta = Utils.getLastDelta(specialPercentageEvents); + int damageDealt = -1; if (stave != null && stave.getAnimations().contains(curAnimation)) { + damageDealt = computeDamage(Utils.getAttackStyle(client), AttackProcedure.POWERED_STAVE, curAnimation); // We are currently dealing with a staves in which case we can make decisions based on the // spellbook flag. We can only improve this by using a deprecated API to check the projectile // matches the stave rather than a manual spell, but this is good enough for now. - return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.POWERED_STAVE, 4); + return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.POWERED_STAVE, damageDealt, specDelta, 4); } if (matchesSpellbook && isManualCasting(curAnimation)) { + damageDealt = computeDamage(Utils.getAttackStyle(client), AttackProcedure.MANUAL_AUTO_CAST, curAnimation); // You can cast with anything equipped in which case we shouldn't look to invent for speed. - return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MANUAL_AUTO_CAST, getMagicBaseSpeed(weaponId)); + return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MANUAL_AUTO_CAST, damageDealt, specDelta,getMagicBaseSpeed(weaponId)); } + damageDealt = computeDamage(Utils.getAttackStyle(client), AttackProcedure.MELEE_OR_RANGE, curAnimation); ItemStats weaponStats = getWeaponStats(weaponId); if (weaponStats == null) { - return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MELEE_OR_RANGE, 4); // Assume barehanded == 4t + return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MELEE_OR_RANGE, damageDealt, specDelta, 4); // Assume barehanded == 4t } // Deadline for next available attack. - return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MELEE_OR_RANGE, weaponStats.getEquipment().getAspeed()); + return VariableSpeed.computeSpeed(client, curAnimation, AttackProcedure.MELEE_OR_RANGE, damageDealt, specDelta, weaponStats.getEquipment().getAspeed()); } private static final List SPECIAL_NPCS = Arrays.asList(10507, 9435, 9438, 9441, 9444); // Combat Dummy + Nightmare Pillars @@ -438,6 +524,7 @@ public void onChatMessage(ChatMessage event) // We should always add eat delay pendingEatDelayTicks += attackDelay; } + VariableSpeed.onChatMessage(event); } // onInteractingChanged is the driver for detecting if the player attacked out side the usual tick window @@ -523,6 +610,17 @@ public void onGameTick(GameTick tick) // clamp the attackDelayHoldoffTicks at -20, this is so we correctly account for eats even when not // attacking, but don't count down forever. attackDelayHoldoffTicks = Math.max(-20, attackDelayHoldoffTicks - 1); + if (specialPercentageEvents.size() > 5) + { + specialPercentageEvents.removeFirst(); + } + for (var q : combatExpEarned.values()) + { + if (q.size() > 5) + { + q.removeFirst(); + } + } } @@ -551,6 +649,7 @@ protected void shutDown() throws Exception attackDelayHoldoffTicks = 0; } + @VisibleForTesting public void writeState(ByteArrayDataOutput outChannel) { StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/com/attacktimer/ClientUtils/Utils.java b/src/main/java/com/attacktimer/ClientUtils/Utils.java index dbb5bab..e82bfd8 100644 --- a/src/main/java/com/attacktimer/ClientUtils/Utils.java +++ b/src/main/java/com/attacktimer/ClientUtils/Utils.java @@ -29,17 +29,20 @@ import com.attacktimer.AttackStyle; import com.attacktimer.AttackType; import com.attacktimer.WeaponType; +import java.util.ArrayDeque; import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; import net.runelite.api.NPC; -import net.runelite.api.VarPlayer; -import net.runelite.api.Varbits; +import net.runelite.api.WorldView; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.InventoryID; +import net.runelite.api.gameval.VarPlayerID; +import net.runelite.api.gameval.VarbitID; +import org.apache.commons.lang3.ArrayUtils; public class Utils { @@ -55,7 +58,7 @@ public static int getItemIdFromContainer(ItemContainer container, int slotID) public static int getWeaponId(Client client) { - return getItemIdFromContainer(client.getItemContainer(InventoryID.EQUIPMENT), + return getItemIdFromContainer(client.getItemContainer(InventoryID.WORN), EquipmentInventorySlot.WEAPON.getSlotIdx()); } @@ -72,9 +75,18 @@ public static WorldPoint getLocation(Client client) public static AttackStyle getAttackStyle(Client client) { final AttackStyle[] attackStyles = getWeaponType(client).getAttackStyles(client); - final int currentAttackStyleVarbit = client.getVarpValue(VarPlayer.ATTACK_STYLE); + System.out.println("getAttackStyle attackStyles (DEFENCE): " + attackStyles.toString()); + int currentAttackStyleVarbit = client.getVarpValue(VarPlayerID.COM_MODE); + final int castingMode = client.getVarbitValue(VarbitID.AUTOCAST_DEFMODE); if (currentAttackStyleVarbit < attackStyles.length) { + // from script4525 + // Even though the client has 5 attack styles for Staffs, only attack styles 0-4 are used, with an additional + // casting mode set for defensive casting + if (currentAttackStyleVarbit == 4) + { + currentAttackStyleVarbit += castingMode; + } return attackStyles[currentAttackStyleVarbit]; } @@ -84,7 +96,7 @@ public static AttackStyle getAttackStyle(Client client) // returns null for unknown weapons public static WeaponType getWeaponType(Client client) { - final int currentEquippedWeaponTypeVarbit = client.getVarbitValue(Varbits.EQUIPPED_WEAPON_TYPE); + final int currentEquippedWeaponTypeVarbit = client.getVarbitValue(VarbitID.COMBAT_WEAPON_CATEGORY); return WeaponType.getWeaponType(currentEquippedWeaponTypeVarbit); } @@ -92,7 +104,7 @@ public static WeaponType getWeaponType(Client client) public static AttackType getAttackType(Client client) { final WeaponType weaponType = getWeaponType(client); - final int currentAttackStyleVarbit = client.getVarpValue(VarPlayer.ATTACK_STYLE); + final int currentAttackStyleVarbit = client.getVarpValue(VarPlayerID.COM_MODE); if (currentAttackStyleVarbit < weaponType.getAttackTypes().length) { return weaponType.getAttackTypes()[currentAttackStyleVarbit]; @@ -124,4 +136,40 @@ public static NPC getTargetNPC(Client client) return null; } + // TODO comment + public static boolean isInRegionId(Client client, int id) + { + WorldView wv = client.getTopLevelWorldView(); + if (wv == null) + { + return false; + } + + int[] regions = wv.getMapRegions(); + if (regions == null || regions.length == 0) + { + return false; + } + + return ArrayUtils.contains(regions, id); + } + + // TODO comment + public static int getLastDelta(ArrayDeque events) + { + int i = 0, last = -1, secondLast = -1; + var it = events.descendingIterator(); + while (it.hasNext()) + { + if (i == 0) + last = it.next(); + else if (i == 1) + secondLast = it.next(); + else + break; + i++; + } + var delta = last - secondLast; + return delta; + } } diff --git a/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java b/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java index 6c06ec5..617a0f9 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java +++ b/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java @@ -27,13 +27,14 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; +import java.util.ArrayDeque; import net.runelite.api.Client; -import net.runelite.api.events.GameTick; + public class BloodMoonSet implements IVariableSpeed { private static final int BLOOD_MOON_SET_ANIM_ID = 2792; - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { if (client.getLocalPlayer().hasSpotAnim(BLOOD_MOON_SET_ANIM_ID)) { @@ -41,5 +42,4 @@ public int apply(final Client client, final AnimationData curAnimation, final At } return curSpeed; } - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java b/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java index c78d314..56e27ad 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java +++ b/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java @@ -27,12 +27,12 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; +import java.util.ArrayDeque; import net.runelite.api.Client; -import net.runelite.api.events.GameTick; public class EyeOfAyak implements IVariableSpeed { - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { // https://oldschool.runescape.wiki/w/Eye_of_ayak#Charged // https://oldschool.runescape.wiki/w/Eye_of_ayak#Special_attack @@ -46,5 +46,4 @@ public int apply(final Client client, final AnimationData curAnimation, final At } return curSpeed; } - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/IVariableSpeed.java b/src/main/java/com/attacktimer/VariableSpeed/IVariableSpeed.java index 0081977..374da4b 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/IVariableSpeed.java +++ b/src/main/java/com/attacktimer/VariableSpeed/IVariableSpeed.java @@ -1,5 +1,6 @@ package com.attacktimer.VariableSpeed; + /* * Copyright (c) 2024, Lexer747 * All rights reserved. @@ -28,6 +29,7 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; import net.runelite.api.Client; +import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; public interface IVariableSpeed @@ -43,13 +45,15 @@ public interface IVariableSpeed * @param curAnimation the animation currently being used to attack. * @param atkType the overarching "attack type" for this attack, this is based on all the inference made * about manual casts, etc. For more details about the attack {@see com.attacktimer.ClientUtils.Utils}. + * + * * @param baseSpeed the speed at which the attack speed started before any other variable speeds have * changed it. * @param curSpeed the current speed at which the attack is now after variable speeds have been applied, * e.g. rapid with range style. * @return the new attack speed if the pre-conditions for this variable attack speed where met. */ - public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int baseSpeed, int curSpeed); + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed); /** * onGameTick is pseudo subscription method, a variable speed implementation can implement this if the * condition for the variable speed requires some larger state tracking and cannot be implemented in apply @@ -57,5 +61,8 @@ public interface IVariableSpeed * @param client the RuneScape client. * @param tick the current tick. */ - public void onGameTick(Client client, GameTick tick); + default public void onGameTick(Client client, GameTick tick) {}; + + // TODO docs + default public void onChatMessage(ChatMessage event) {}; } \ No newline at end of file diff --git a/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java b/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java index 9decc6d..2b6b00f 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java +++ b/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java @@ -30,14 +30,14 @@ import com.attacktimer.AttackProcedure; import com.attacktimer.AttackStyle; import com.attacktimer.ClientUtils.Utils; +import java.util.ArrayDeque; import net.runelite.api.Client; import net.runelite.api.Varbits; import net.runelite.api.WorldType; -import net.runelite.api.events.GameTick; public class Leagues4and5 implements IVariableSpeed { - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { if (!client.getWorldType().contains(WorldType.SEASONAL)) { @@ -85,6 +85,4 @@ else if (masteryLevel >= 3) } return baseSpeed; } - - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java b/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java new file mode 100644 index 0000000..a7b5ad1 --- /dev/null +++ b/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java @@ -0,0 +1,230 @@ +package com.attacktimer.VariableSpeed; + +/* + * Copyright (c) 2026, Lexer747 + * 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. + */ + +import com.attacktimer.AnimationData; +import com.attacktimer.AttackProcedure; +import com.attacktimer.ClientUtils.Utils; +import com.attacktimer.VariableSpeed.PurgingStaffSpec.YamaData; +import com.attacktimer.VariableSpeed.PurgingStaffSpec.YamaPhase; +import lombok.NonNull; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameTick; + +public class PurgingStaffSpec implements IVariableSpeed +{ + + private static final int HP_FUDGE = 2; + + private static final int VOID_FLARE_HP_P1_P2 = 140 - HP_FUDGE; + private static final int VOID_FLARE_HP_P3 = 71 - HP_FUDGE; + private static final int VOID_FLARE_ID = 14179; + + private static final int PURGING_STAFF_ID = 29594; + + private static final int YAMA_REGION_ID = 6045; + private static final int YAMA_ID = 14176; + private static final int YAMA_PHASE_TRANSITION_ANIMATION_ID = 12147; + + private YamaData yama; + private boolean inYamaRegion; + private NPC lastTarget; + + // https://oldschool.runescape.wiki/w/Purging_staff#Special_attack + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) + { + // For now the plugin only works for yama + if (!inYamaRegion) + { + return curSpeed; + } + var target = Utils.getTargetNPC(client); + var flare = isEitherAVoidFlare(target, lastTarget); + lastTarget = target; + if (flare == null) + { + return curSpeed; + } + if (yama == null) + { + return curSpeed; + } + + + System.out.println("damageDealt: " + Integer.valueOf(damageDealt).toString()); + yama.dealVoidFlareDamage(flare, damageDealt); + if (lastSpecDelta != -250) + { + // not using the spec + return curSpeed; + } + if (Utils.getWeaponId(client) != PURGING_STAFF_ID) + { + // not using a purging staff + return curSpeed; + } + + if (yama.getVoidFlareDead(flare)) + { + // speed up! + // according to the wiki this should be 3 ticks but is actually 2 ticks is normal circumstances + return curSpeed - 2; + } + return curSpeed; + } + public void onGameTick(Client client, GameTick tick) + { + inYamaRegion = Utils.isInRegionId(client, YAMA_REGION_ID); + if (!inYamaRegion) + { + yama = null; + return; + } + if (yama != null) + { + yama.determineYamaPhase(); + return; + } + for (NPC npc : client.getTopLevelWorldView().npcs()) + { + if (npc.getId() == YAMA_ID) + { + System.out.println("new yama data"); + yama = new YamaData(npc); + return; + } + } + } + + public void onChatMessage(ChatMessage event) + { + if (!inYamaRegion) return; + if (yama == null) return; + if (event.getMessage().startsWith("Your Yama success count is:")) + { + System.out.println("yama.killed()"); + yama.killed(); + } + } + + private static NPC isEitherAVoidFlare(NPC a, NPC b) + { + if (a != null && a.getId() == VOID_FLARE_ID) return a; + if (b != null && b.getId() == VOID_FLARE_ID) return b; + return null; + } + + class YamaData + { + @NonNull + NPC yama; + YamaPhase phase; + int phaseChangeCooldown; + Map voidFlares; + YamaData(NPC yama) + { + this.yama = yama; + this.phase = YamaPhase.P1; + this.phaseChangeCooldown = 0; + this.voidFlares = new HashMap(); + } + + public boolean getVoidFlareDead(NPC target) + { + if (!this.voidFlares.containsKey(target)) return false; + Boolean dead = this.voidFlares.get(target) <= 0; + System.out.println("getVoidFlareDead => "+dead.toString()); + return dead; + } + + public void dealVoidFlareDamage(NPC target, int damageDealt) + { + if (this.voidFlares.containsKey(target)) + { + this.voidFlares.put(target, this.voidFlares.get(target)-damageDealt); + } + else + { + var hp = this.getVoidFlareHp()-damageDealt; + System.out.println("tracking new void flare, started with "+ this.getVoidFlareHp()+" hp - "+damageDealt+" total: "+hp+" hp"); + this.voidFlares.put(target, hp); + } + } + + private void determineYamaPhase() + { + if (phaseChangeCooldown == 0 && this.yama.getAnimation() == YAMA_PHASE_TRANSITION_ANIMATION_ID) + { + System.out.println("yama moving to next phase"); + this.phaseChangeCooldown = 20; + this.phase = this.phase.nextPhase(); + } + if (this.phaseChangeCooldown > 0) + this.phaseChangeCooldown--; + } + + private int getVoidFlareHp() + { + switch (this.phase) { + case P1: + case P2: + return VOID_FLARE_HP_P1_P2; + default: + return VOID_FLARE_HP_P3; + } + } + + private void killed() + { + this.phase = YamaPhase.P1; + } + } + + enum YamaPhase { + P1, + P2, + P3; + + private YamaPhase nextPhase() + { + switch (this) { + case P1: + return P2; + case P2: + return P3; + case P3: + return P3; + } + return P1; + } + } +} diff --git a/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java b/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java index 3109531..987c191 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java +++ b/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java @@ -30,22 +30,21 @@ import com.attacktimer.AttackProcedure; import com.attacktimer.AttackStyle; import com.attacktimer.ClientUtils.Utils; +import java.util.ArrayDeque; import net.runelite.api.Client; import net.runelite.api.VarPlayer; -import net.runelite.api.events.GameTick; public class RapidAttackStyle implements IVariableSpeed { - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { // index 1 == rapid final boolean isRapid = client.getVarpValue(VarPlayer.ATTACK_STYLE) == 1; - if (atkProcedure == AttackProcedure.MELEE_OR_RANGE && Utils.getAttackStyle(client) == AttackStyle.RANGING && isRapid) + if (atkType == AttackProcedure.MELEE_OR_RANGE && Utils.getAttackStyle(client) == AttackStyle.RANGING && isRapid) { // Also works for salamanders which attack 1 tick faster when using the ranged style return curSpeed-1; } return curSpeed; } - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/RedKerisSpec.java b/src/main/java/com/attacktimer/VariableSpeed/RedKerisSpec.java index a0e5d93..0f5c759 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/RedKerisSpec.java +++ b/src/main/java/com/attacktimer/VariableSpeed/RedKerisSpec.java @@ -28,11 +28,10 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; import net.runelite.api.Client; -import net.runelite.api.events.GameTick; public class RedKerisSpec implements IVariableSpeed { - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { if (curAnimation == AnimationData.MELEE_RED_KERIS_SPEC) { @@ -41,5 +40,4 @@ public int apply(final Client client, final AnimationData curAnimation, final At } return curSpeed; } - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/Scurrius.java b/src/main/java/com/attacktimer/VariableSpeed/Scurrius.java index a3dbe64..fcd6b0c 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/Scurrius.java +++ b/src/main/java/com/attacktimer/VariableSpeed/Scurrius.java @@ -30,7 +30,6 @@ import com.attacktimer.ClientUtils.Utils; import net.runelite.api.Client; import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.GameTick; /** * Scurrius: https://oldschool.runescape.wiki/w/Scurrius/Strategies#Strategies @@ -62,7 +61,7 @@ private static boolean attackingGiantRatWithBoneWeapon(final int equipped, final return correctWeapon && correctCoords && correctRegion && correctEnemy; } - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { final WorldPoint location = Utils.getLocation(client); final int weaponId = Utils.getWeaponId(client); @@ -73,5 +72,4 @@ public int apply(final Client client, final AnimationData curAnimation, final At } return curSpeed; } - public void onGameTick(final Client client, final GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/TombsOfAmascut.java b/src/main/java/com/attacktimer/VariableSpeed/TombsOfAmascut.java index 8277f49..5ddcc2f 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/TombsOfAmascut.java +++ b/src/main/java/com/attacktimer/VariableSpeed/TombsOfAmascut.java @@ -30,7 +30,6 @@ import com.attacktimer.AttackType; import com.attacktimer.ClientUtils.Utils; import net.runelite.api.Client; -import net.runelite.api.events.GameTick; /** * There is no cooldown when attacking the skulls with melee. @@ -41,7 +40,7 @@ public class TombsOfAmascut implements IVariableSpeed // https://oldschool.runescape.wiki/w/Energy_Siphon private static final int ENERGY_SIPHON_ID = 11772; - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { final int targetId = Utils.getTargetId(client); final AttackType attkType = Utils.getAttackType(client); @@ -51,5 +50,4 @@ public int apply(final Client client, final AnimationData curAnimation, final At } return curSpeed; } - public void onGameTick(Client client, GameTick tick) {} } diff --git a/src/main/java/com/attacktimer/VariableSpeed/TormentedDemons.java b/src/main/java/com/attacktimer/VariableSpeed/TormentedDemons.java index 98ec413..66c6a73 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/TormentedDemons.java +++ b/src/main/java/com/attacktimer/VariableSpeed/TormentedDemons.java @@ -56,7 +56,7 @@ */ public class TormentedDemons implements IVariableSpeed { - public int apply(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed, final int curSpeed) + public int apply(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed, int curSpeed) { int targetId = Utils.getTargetId(client); if (!isTormentedDemon(targetId)) @@ -81,7 +81,7 @@ public int apply(final Client client, final AnimationData curAnimation, final At return curSpeed; } // Finally the last checks, only certain attack styles and weapons can trigger the effect. - switch (atkProcedure) + switch (atkType) { case POWERED_STAVE: // Powered staves cannot trigger the effect diff --git a/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java b/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java index 21f3ede..7e8a773 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java +++ b/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java @@ -28,6 +28,7 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; import net.runelite.api.Client; +import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; public class VariableSpeed @@ -35,18 +36,13 @@ public class VariableSpeed /** * computeSpeed will forward the client, animation data and current weapon speed to all the known classes * which can affect the base speed of a weapon. See implementations of IVariableSpeed. - * @param client - * @param curAnimation - * @param atkType - * @param baseSpeed - * @return */ - public static int computeSpeed(final Client client, final AnimationData curAnimation, final AttackProcedure atkProcedure, final int baseSpeed) + public static int computeSpeed(Client client, AnimationData curAnimation, AttackProcedure atkType, int damageDealt, int lastSpecDelta, int baseSpeed) { int newSpeed = baseSpeed; for (IVariableSpeed i : TO_APPLY) { - newSpeed = i.apply(client, curAnimation, atkProcedure, baseSpeed, newSpeed); + newSpeed = i.apply(client, curAnimation, atkType, damageDealt, lastSpecDelta, baseSpeed, newSpeed); } return newSpeed; } @@ -59,6 +55,14 @@ public static void onGameTick(Client client, GameTick tick) } } + public static void onChatMessage(ChatMessage event) + { + for (IVariableSpeed i : TO_APPLY) + { + i.onChatMessage(event); + } + } + private static final IVariableSpeed[] TO_APPLY = { // Order matters, apply leagues first, then any incremental modifications like rapid, or set effects. // Then overriding speeds last, which set a speed. @@ -68,6 +72,7 @@ public static void onGameTick(Client client, GameTick tick) new BloodMoonSet(), new RapidAttackStyle(), new RedKerisSpec(), + new PurgingStaffSpec(), new EyeOfAyak(), new TormentedDemons(), From 9cd012cc56f7e7fe5b53661a03eebae56b0b0c93 Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Thu, 16 Apr 2026 19:58:39 +0100 Subject: [PATCH 2/2] lint and clean up --- .github/pull_request_template.md | 4 +-- .../AttackTimerMetronomePlugin.java | 15 ++++++----- .../com/attacktimer/ClientUtils/Utils.java | 1 - .../VariableSpeed/BloodMoonSet.java | 1 - .../attacktimer/VariableSpeed/EyeOfAyak.java | 1 - .../VariableSpeed/Leagues4and5.java | 1 - .../VariableSpeed/PurgingStaffSpec.java | 26 +++++++------------ .../VariableSpeed/RapidAttackStyle.java | 1 - 8 files changed, 19 insertions(+), 31 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1cc7d1f..9bbe422 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,7 +4,7 @@ Please explain in reasonable detail what your series of changes does, and how it does it. Make sure to link any relevant github issues which instigated your changes. -you can safely leave delete this comment as you fill out this text box. +you can safely leave or delete this comment as you fill out this text box. Please leave the Summary and Testing sub titles. --> @@ -14,6 +14,6 @@ Please leave the Summary and Testing sub titles. DO NOT leave this section empty, please add any relevant testing evidence (in game, unit tests, etc) that show that your changes achieve the desired effect. -you can safely leave delete this comment as you fill out this text box. +you can safely leave or delete this comment as you fill out this text box. Please leave the Summary and Testing sub titles. --> \ No newline at end of file diff --git a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java index 8d8ce50..2623ff7 100644 --- a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java +++ b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java @@ -1,6 +1,5 @@ package com.attacktimer; -import com.attacktimer.ClientUtils.Utils; /* * Copyright (c) 2022, Nick Graves @@ -29,6 +28,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import com.attacktimer.ClientUtils.Utils; import com.attacktimer.VariableSpeed.VariableSpeed; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; @@ -48,7 +48,6 @@ import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.GameState; import net.runelite.api.Item; import net.runelite.api.ItemContainer; import net.runelite.api.NPC; @@ -289,16 +288,19 @@ AttackTimerMetronomeConfig provideConfig(ConfigManager configManager) private int computeDamage(AttackStyle attackStyle, AttackProcedure atkType, AnimationData curAnimation) { - switch (atkType) { + switch (atkType) + { case POWERED_STAVE: // TODO not needed for any variable speed return -1; case MANUAL_AUTO_CAST: - if (attackStyle == AttackStyle.DEFENSIVE_CASTING || attackStyle == AttackStyle.DEFENSIVE) { + if (attackStyle == AttackStyle.DEFENSIVE_CASTING || attackStyle == AttackStyle.DEFENSIVE) + { // just use the defense exp to compute the damage - System.out.println("computeDamage (DEFENCE): " + Utils.getLastDelta(combatExpEarned.get(Skill.DEFENCE)) + " | " + combatExpEarned.get(Skill.DEFENCE)); return Utils.getLastDelta(combatExpEarned.get(Skill.DEFENCE)); - } else { + } + else + { // deduct the fixed exp based on the spell // (for now this only works for dark demon bane which awkwardly gives fractional exp) var mageExp = Utils.getLastDelta(combatExpEarned.get(Skill.MAGIC)); @@ -306,7 +308,6 @@ private int computeDamage(AttackStyle attackStyle, AttackProcedure atkType, Anim { return -1; } - System.out.println("computeDamage (MAGIC): " + Utils.getLastDelta(combatExpEarned.get(Skill.MAGIC)) + " | " + combatExpEarned.get(Skill.MAGIC)); return (int) Math.ceil(((double) mageExp - 43.5D) / 2.0D); } case MELEE_OR_RANGE: diff --git a/src/main/java/com/attacktimer/ClientUtils/Utils.java b/src/main/java/com/attacktimer/ClientUtils/Utils.java index e82bfd8..caa9637 100644 --- a/src/main/java/com/attacktimer/ClientUtils/Utils.java +++ b/src/main/java/com/attacktimer/ClientUtils/Utils.java @@ -75,7 +75,6 @@ public static WorldPoint getLocation(Client client) public static AttackStyle getAttackStyle(Client client) { final AttackStyle[] attackStyles = getWeaponType(client).getAttackStyles(client); - System.out.println("getAttackStyle attackStyles (DEFENCE): " + attackStyles.toString()); int currentAttackStyleVarbit = client.getVarpValue(VarPlayerID.COM_MODE); final int castingMode = client.getVarbitValue(VarbitID.AUTOCAST_DEFMODE); if (currentAttackStyleVarbit < attackStyles.length) diff --git a/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java b/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java index 617a0f9..c958810 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java +++ b/src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java @@ -27,7 +27,6 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; -import java.util.ArrayDeque; import net.runelite.api.Client; diff --git a/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java b/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java index 56e27ad..c6ddc54 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java +++ b/src/main/java/com/attacktimer/VariableSpeed/EyeOfAyak.java @@ -27,7 +27,6 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; -import java.util.ArrayDeque; import net.runelite.api.Client; public class EyeOfAyak implements IVariableSpeed diff --git a/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java b/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java index 2b6b00f..e546796 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java +++ b/src/main/java/com/attacktimer/VariableSpeed/Leagues4and5.java @@ -30,7 +30,6 @@ import com.attacktimer.AttackProcedure; import com.attacktimer.AttackStyle; import com.attacktimer.ClientUtils.Utils; -import java.util.ArrayDeque; import net.runelite.api.Client; import net.runelite.api.Varbits; import net.runelite.api.WorldType; diff --git a/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java b/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java index a7b5ad1..9342a23 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java +++ b/src/main/java/com/attacktimer/VariableSpeed/PurgingStaffSpec.java @@ -28,13 +28,9 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; import com.attacktimer.ClientUtils.Utils; -import com.attacktimer.VariableSpeed.PurgingStaffSpec.YamaData; -import com.attacktimer.VariableSpeed.PurgingStaffSpec.YamaPhase; -import lombok.NonNull; -import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import lombok.NonNull; import net.runelite.api.Client; import net.runelite.api.NPC; import net.runelite.api.events.ChatMessage; @@ -68,7 +64,7 @@ public int apply(Client client, AnimationData curAnimation, AttackProcedure atkT return curSpeed; } var target = Utils.getTargetNPC(client); - var flare = isEitherAVoidFlare(target, lastTarget); + var flare = isEitherVoidFlare(target, lastTarget); lastTarget = target; if (flare == null) { @@ -79,8 +75,6 @@ public int apply(Client client, AnimationData curAnimation, AttackProcedure atkT return curSpeed; } - - System.out.println("damageDealt: " + Integer.valueOf(damageDealt).toString()); yama.dealVoidFlareDamage(flare, damageDealt); if (lastSpecDelta != -250) { @@ -118,7 +112,6 @@ public void onGameTick(Client client, GameTick tick) { if (npc.getId() == YAMA_ID) { - System.out.println("new yama data"); yama = new YamaData(npc); return; } @@ -131,12 +124,11 @@ public void onChatMessage(ChatMessage event) if (yama == null) return; if (event.getMessage().startsWith("Your Yama success count is:")) { - System.out.println("yama.killed()"); yama.killed(); } } - private static NPC isEitherAVoidFlare(NPC a, NPC b) + private static NPC isEitherVoidFlare(NPC a, NPC b) { if (a != null && a.getId() == VOID_FLARE_ID) return a; if (b != null && b.getId() == VOID_FLARE_ID) return b; @@ -162,7 +154,6 @@ public boolean getVoidFlareDead(NPC target) { if (!this.voidFlares.containsKey(target)) return false; Boolean dead = this.voidFlares.get(target) <= 0; - System.out.println("getVoidFlareDead => "+dead.toString()); return dead; } @@ -175,7 +166,6 @@ public void dealVoidFlareDamage(NPC target, int damageDealt) else { var hp = this.getVoidFlareHp()-damageDealt; - System.out.println("tracking new void flare, started with "+ this.getVoidFlareHp()+" hp - "+damageDealt+" total: "+hp+" hp"); this.voidFlares.put(target, hp); } } @@ -184,7 +174,6 @@ private void determineYamaPhase() { if (phaseChangeCooldown == 0 && this.yama.getAnimation() == YAMA_PHASE_TRANSITION_ANIMATION_ID) { - System.out.println("yama moving to next phase"); this.phaseChangeCooldown = 20; this.phase = this.phase.nextPhase(); } @@ -194,7 +183,8 @@ private void determineYamaPhase() private int getVoidFlareHp() { - switch (this.phase) { + switch (this.phase) + { case P1: case P2: return VOID_FLARE_HP_P1_P2; @@ -209,14 +199,16 @@ private void killed() } } - enum YamaPhase { + enum YamaPhase + { P1, P2, P3; private YamaPhase nextPhase() { - switch (this) { + switch (this) + { case P1: return P2; case P2: diff --git a/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java b/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java index 987c191..7dc8d47 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java +++ b/src/main/java/com/attacktimer/VariableSpeed/RapidAttackStyle.java @@ -30,7 +30,6 @@ import com.attacktimer.AttackProcedure; import com.attacktimer.AttackStyle; import com.attacktimer.ClientUtils.Utils; -import java.util.ArrayDeque; import net.runelite.api.Client; import net.runelite.api.VarPlayer;