From 763225c1592be611e981a780b405e5f12d01126f Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Wed, 2 Sep 2026 17:14:24 +0100 Subject: [PATCH 1/5] account for the sticky bile --- .../com/attacktimer/AttackTimerMetronomePlugin.java | 1 + .../com/attacktimer/VariableSpeed/MaggotKing.java | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java index 1f26ee8..e3ba573 100644 --- a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java +++ b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java @@ -234,6 +234,7 @@ else if (SLOW_FOOD.matcher(message).find()) pendingEatDelayTicks += attackDelay; } VariableSpeed.onChatMessage(client, event); + attackDelayHoldoffTicks = VariableSpeed.MAGGOT_KING.onChatMessage(client, message, attackDelayHoldoffTicks); } // endregion diff --git a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java index a418b07..7361704 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java +++ b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java @@ -88,4 +88,15 @@ public int onRender(final Client client, final ItemManager itemManager, final in consumed = tickCount.get(); return attackSpeed.compute(client, anim, spellbook, itemManager); } + + public int onChatMessage(final Client client, final String message, final int attackDelayHoldoffTicks) + { + // https://oldschool.runescape.wiki/w/Maggot_King/Strategies#Fight_overview + // Standing on the sticky bile will ... delay the player's next attack by one tick. + if (message.equals("The sticky acid hampers your ability to attack!")) + { + return attackDelayHoldoffTicks+1; + } + return attackDelayHoldoffTicks; + } } From 02a8e365220d75c0c4a826da255d48ebae35ac80 Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Thu, 3 Sep 2026 23:20:54 +0100 Subject: [PATCH 2/5] simplify implementation just call performAttack() --- .../AttackTimerMetronomePlugin.java | 9 ++-- .../VariableSpeed/DoomOfMokhaiotl.java | 25 +++++------ .../attacktimer/VariableSpeed/MaggotKing.java | 44 +++++++++++-------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java index e3ba573..2bb4465 100644 --- a/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java +++ b/src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java @@ -234,7 +234,7 @@ else if (SLOW_FOOD.matcher(message).find()) pendingEatDelayTicks += attackDelay; } VariableSpeed.onChatMessage(client, event); - attackDelayHoldoffTicks = VariableSpeed.MAGGOT_KING.onChatMessage(client, message, attackDelayHoldoffTicks); + pendingEatDelayTicks += VariableSpeed.MAGGOT_KING.onChatMessage(client, message); } // endregion @@ -464,8 +464,11 @@ public void onRender() attackState = AttackState.NOT_ATTACKING; } } - attackDelayHoldoffTicks = VariableSpeed.MAGGOT_KING.onRender(client, itemManager, attackDelayHoldoffTicks, currentSpellBook, config.debugLogs()); - attackDelayHoldoffTicks = VariableSpeed.DOOM_OF_MOKHAIOTL.onRender(client, itemManager, attackDelayHoldoffTicks, currentSpellBook, config.debugLogs()); + if (VariableSpeed.MAGGOT_KING.onRender(client, itemManager, config.debugLogs()) + || VariableSpeed.DOOM_OF_MOKHAIOTL.onRender(client, itemManager, currentSpellBook, config.debugLogs())) + { + performAttack(); + } checkForLateWeaponSwaps(); } diff --git a/src/main/java/com/attacktimer/VariableSpeed/DoomOfMokhaiotl.java b/src/main/java/com/attacktimer/VariableSpeed/DoomOfMokhaiotl.java index 1c15e33..ddad9be 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/DoomOfMokhaiotl.java +++ b/src/main/java/com/attacktimer/VariableSpeed/DoomOfMokhaiotl.java @@ -27,7 +27,6 @@ import com.attacktimer.AnimationData; import com.attacktimer.AttackProcedure; -import com.attacktimer.AttackSpeed; import com.attacktimer.Attacking.Attacking; import com.attacktimer.ClientUtils.Utils; import com.attacktimer.Spellbook; @@ -78,14 +77,12 @@ public class DoomOfMokhaiotl implements IVariableSpeed .build(); private final TickCount tickCount; - private final AttackSpeed attackSpeed; private int larvaeConsumed = -1; private int shieldConsumed = -1; - DoomOfMokhaiotl(final TickCount tc, final AttackSpeed attackSpeed) + DoomOfMokhaiotl(final TickCount tc) { this.tickCount = tc; - this.attackSpeed = attackSpeed; } // https://oldschool.runescape.wiki/w/Doom_of_Mokhaiotl/Strategies#Demonic_larvae @@ -97,18 +94,18 @@ public class DoomOfMokhaiotl implements IVariableSpeed // // The https://oldschool.runescape.wiki/w/Volatile_earth also has the same larvae mechanics and allow list // of items. - public int onRender(final Client client, final ItemManager itemManager, final int attackDelayHoldoffTicks, final Spellbook spellbook, final boolean debugLogs) + public boolean onRender(final Client client, final ItemManager itemManager, final Spellbook spellbook, final boolean debugLogs) { if (!Utils.isInRegionId(client, DOOM_REGION_IDS)) { - return attackDelayHoldoffTicks; + return false; } final var atk = Attacking.PlayerAttack(client); final AnimationData anim = AnimationData.fromId(atk.getAnimationId()); if (anim == null || atk.getTarget() == null || !(atk.getTarget() instanceof NPC) || anim.isBlockListAnimation()) { - return attackDelayHoldoffTicks; + return false; } final NPC npc = (NPC) atk.getTarget(); @@ -117,13 +114,13 @@ public int onRender(final Client client, final ItemManager itemManager, final in { if (tickCount.isWithinNTicks(larvaeConsumed, 1)) { - return attackDelayHoldoffTicks; + return false; } final int weaponId = Utils.getWeaponId(client); final boolean isDemonbaneSpell = spellbook == Spellbook.ARCEUUS && AnimationData.isManualCasting(anim) && anim == AnimationData.MAGIC_ARCEUUS_DEMONBANE; if (NO_COOLDOWN_WEAPON.contains(weaponId) || isDemonbaneSpell) { - return attackDelayHoldoffTicks; + return false; } if (debugLogs) @@ -131,13 +128,13 @@ public int onRender(final Client client, final ItemManager itemManager, final in log.debug("DoomOfMokhaiotl success, attacking larvae with normal weapon"); } larvaeConsumed = tickCount.get(); - return attackSpeed.compute(client, anim, spellbook, itemManager); + return true; } else if (npcId == NpcID.DOM_BOSS) { if (tickCount.isWithinNTicks(shieldConsumed, 30)) { - return attackDelayHoldoffTicks; + return false; } final var animId = npc.getAnimation(); // Undocumented in the wiki but from my testing these can be hit while on cooldown but unlike the @@ -160,14 +157,14 @@ else if (npcId == NpcID.DOM_BOSS) log.debug("DoomOfMokhaiotl success, on cooldown melee swing"); } shieldConsumed = tickCount.get(); - return attackSpeed.compute(client, anim, spellbook, itemManager); + return true; } } - return attackDelayHoldoffTicks; + return false; } else { - return attackDelayHoldoffTicks; + return false; } } diff --git a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java index 7361704..134f301 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java +++ b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java @@ -26,10 +26,8 @@ */ import com.attacktimer.AnimationData; -import com.attacktimer.AttackSpeed; import com.attacktimer.Attacking.Attacking; import com.attacktimer.ClientUtils.Utils; -import com.attacktimer.Spellbook; import com.attacktimer.VariableSpeed.State.TickCount; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -44,59 +42,69 @@ public class MaggotKing private static final int MAGGOT_KING_REGION_ID = 11645; private final TickCount tickCount; - private final AttackSpeed attackSpeed; // the tick count if a larvae was hit, this is purely to debounce private int consumed = -1; - MaggotKing(final TickCount tc, final AttackSpeed attackSpeed) + MaggotKing(final TickCount tc) { this.tickCount = tc; - this.attackSpeed = attackSpeed; } // https://oldschool.runescape.wiki/w/Maggot_King/Strategies#Ur-maggot_larvae // - // If the player attacks a maggot with a "standard bow" it doesn't matter what current cooldown is the + // If the player attacks a maggot with a "standard bow" it doesn't matter what current cooldown is + // the // player is immediately set to the cooldown of the bow they used. // - // Therefore this method returns `attackDelayHoldoffTicks` in all cases where this condition isn't met. - // But if the condition is met this method returns a brand new number which is the attack speed of the bow + // Therefore this method returns `attackDelayHoldoffTicks` in all cases where this condition isn't + // met. + // But if the condition is met this method returns a brand new number which is the attack speed of + // the bow // used. This number can be the same as the current delay and that's ok. - public int onRender(final Client client, final ItemManager itemManager, final int attackDelayHoldoffTicks, final Spellbook spellbook, final boolean debugLogs) + public boolean onRender(final Client client, final ItemManager itemManager, final boolean debugLogs) { if (!Utils.isInRegionId(client, MAGGOT_KING_REGION_ID) || tickCount.isWithinNTicks(consumed, 1)) { - return attackDelayHoldoffTicks; + return false; } final var atk = Attacking.PlayerAttack(client); final AnimationData anim = AnimationData.fromId(atk.getAnimationId()); if (anim == null || atk.getTarget() == null || !(atk.getTarget() instanceof NPC)) { - return attackDelayHoldoffTicks; + return false; } final NPC npc = (NPC) atk.getTarget(); - if (npc.getId() != NpcID.UR_MAGGOT_LARVAE || !anim.isStandardBowAttack() || npc.getAnimation() != AnimationID.UR_MAGGOT_LARVAE_FLY) + if (npc.getId() != NpcID.UR_MAGGOT_LARVAE || !anim.isStandardBowAttack() + || npc.getAnimation() != AnimationID.UR_MAGGOT_LARVAE_FLY) { - return attackDelayHoldoffTicks; + return false; } + consumed = tickCount.get(); if (debugLogs) { log.debug("MaggotKing success, attacking flying maggot with bow"); } - consumed = tickCount.get(); - return attackSpeed.compute(client, anim, spellbook, itemManager); + return true; } - public int onChatMessage(final Client client, final String message, final int attackDelayHoldoffTicks) + public int onChatMessage(final Client client, final String message) { // https://oldschool.runescape.wiki/w/Maggot_King/Strategies#Fight_overview // Standing on the sticky bile will ... delay the player's next attack by one tick. if (message.equals("The sticky acid hampers your ability to attack!")) { - return attackDelayHoldoffTicks+1; + log.debug("MaggotKing sticky acid"); + return 1; + } + // this isn't in the wiki but being screeched at also slows down attack speed, more significantly than + // the bile. Each screech instance causes the effect for a total of 9 extra ticks if all goes wrong. + else if (message.equals("The Maggot King's screech disrupts your concentration!")) + { + log.debug("MaggotKing screech"); + return 3; } - return attackDelayHoldoffTicks; + return 0; } } From b919b1acabddb659eea46b2d37187a5690351945 Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Sat, 5 Sep 2026 09:53:44 +0100 Subject: [PATCH 3/5] fix compile --- .../java/com/attacktimer/VariableSpeed/VariableSpeed.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java b/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java index 8e8496d..3b1fb57 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java +++ b/src/main/java/com/attacktimer/VariableSpeed/VariableSpeed.java @@ -109,8 +109,8 @@ public static void onNpcDespawned(final Client client, final NpcDespawned npcDes // Variable speed that doesn't neatly fit in to the IVariable speed pattern (it's not weapon related // but boss related). public static final ShadowCrash SHADOW_CRASH = new ShadowCrash(YAMA, MARK_OF_DARKNESS, AttackTimerMetronomePlugin.TC); - public static final MaggotKing MAGGOT_KING = new MaggotKing(AttackTimerMetronomePlugin.TC, AttackTimerMetronomePlugin.ATTACK_SPEED); - public static final DoomOfMokhaiotl DOOM_OF_MOKHAIOTL = new DoomOfMokhaiotl(AttackTimerMetronomePlugin.TC, AttackTimerMetronomePlugin.ATTACK_SPEED); + public static final MaggotKing MAGGOT_KING = new MaggotKing(AttackTimerMetronomePlugin.TC); + public static final DoomOfMokhaiotl DOOM_OF_MOKHAIOTL = new DoomOfMokhaiotl(AttackTimerMetronomePlugin.TC); private static final IStateTracker[] TO_TRACK = { // State tracking, these do not contribute themselves to any variable speed weapon/mechanic but From b79b1acc1481d9c8e2ca345ea5b302f6a5b3c99f Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Sat, 5 Sep 2026 11:08:19 +0100 Subject: [PATCH 4/5] verion bump --- runelite-plugin.properties | 2 +- src/main/java/com/attacktimer/AttackTimerMetronomeConfig.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runelite-plugin.properties b/runelite-plugin.properties index 34997c5..75a86d1 100644 --- a/runelite-plugin.properties +++ b/runelite-plugin.properties @@ -1,7 +1,7 @@ displayName=AttackTimer author=ngraves95,Lexer747 build=standard -version=1.3.1 +version=1.3.2 description=A plugin to countdown until your next attack tags=pvm,timer,attack,combat,weapon plugins=com.attacktimer.AttackTimerMetronomePlugin \ No newline at end of file diff --git a/src/main/java/com/attacktimer/AttackTimerMetronomeConfig.java b/src/main/java/com/attacktimer/AttackTimerMetronomeConfig.java index e6fe659..1b4c2f3 100644 --- a/src/main/java/com/attacktimer/AttackTimerMetronomeConfig.java +++ b/src/main/java/com/attacktimer/AttackTimerMetronomeConfig.java @@ -275,7 +275,7 @@ default boolean debugLogs() @ConfigItem( position = 10000, keyName = "attacktimerVersion", - name = "Plugin version: v1.3.1", + name = "Plugin version: v1.3.2", description = "" ) default void version() From 499e295dec4a63797d3cda75e6075d9624076d68 Mon Sep 17 00:00:00 2001 From: Lexer747 Date: Sat, 5 Sep 2026 11:22:18 +0100 Subject: [PATCH 5/5] fix string matching --- .../com/attacktimer/VariableSpeed/MaggotKing.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java index 134f301..8a77c2f 100644 --- a/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java +++ b/src/main/java/com/attacktimer/VariableSpeed/MaggotKing.java @@ -52,14 +52,11 @@ public class MaggotKing // https://oldschool.runescape.wiki/w/Maggot_King/Strategies#Ur-maggot_larvae // - // If the player attacks a maggot with a "standard bow" it doesn't matter what current cooldown is - // the + // If the player attacks a maggot with a "standard bow" it doesn't matter what current cooldown is the // player is immediately set to the cooldown of the bow they used. // - // Therefore this method returns `attackDelayHoldoffTicks` in all cases where this condition isn't - // met. - // But if the condition is met this method returns a brand new number which is the attack speed of - // the bow + // Therefore this method returns `attackDelayHoldoffTicks` in all cases where this condition isn't met. + // But if the condition is met this method returns a brand new number which is the attack speed of the bow // used. This number can be the same as the current delay and that's ok. public boolean onRender(final Client client, final ItemManager itemManager, final boolean debugLogs) { @@ -93,14 +90,16 @@ public int onChatMessage(final Client client, final String message) { // https://oldschool.runescape.wiki/w/Maggot_King/Strategies#Fight_overview // Standing on the sticky bile will ... delay the player's next attack by one tick. - if (message.equals("The sticky acid hampers your ability to attack!")) + if (message.contains("The sticky acid hampers your ability to attack!")) { log.debug("MaggotKing sticky acid"); return 1; } // this isn't in the wiki but being screeched at also slows down attack speed, more significantly than // the bile. Each screech instance causes the effect for a total of 9 extra ticks if all goes wrong. - else if (message.equals("The Maggot King's screech disrupts your concentration!")) + // + // note don't use equals colouring of messages breaks stuff: e.g.: '@mes_hl_red@The Maggot King's screech disrupts your concentration!' but it has also been + else if (message.contains("The Maggot King's screech disrupts your concentration!")) { log.debug("MaggotKing screech"); return 3;