Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
445 changes: 227 additions & 218 deletions src/main/java/com/attacktimer/AnimationData.java

Large diffs are not rendered by default.

29 changes: 28 additions & 1 deletion src/main/java/com/attacktimer/AttackBarStyle.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
package com.attacktimer;

/*
* Copyright (c) 2026, Pedro Alves <https://github.com/PedroSilvaAlves>
*
* 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 lombok.AllArgsConstructor;
import lombok.Getter;

Expand All @@ -9,7 +35,8 @@ public enum AttackBarStyle
{
AUTO("Auto"),
STANDARD("Standard"),
HIGH_DETAIL("High Detail");
HIGH_DETAIL("High Detail"),
;

private final String name;

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/attacktimer/AttackStyle.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public enum AttackStyle
LONGRANGE("Longrange", Skill.RANGED, Skill.DEFENCE),
CASTING("Casting", Skill.MAGIC),
DEFENSIVE_CASTING("Defensive Casting", Skill.MAGIC, Skill.DEFENCE),
OTHER("Other");
OTHER("Other"),
;

@Getter
private final String name;
Expand Down
28 changes: 9 additions & 19 deletions src/main/java/com/attacktimer/AttackTimerMetronomePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
import net.runelite.api.events.SoundEffectPlayed;
import net.runelite.api.events.StatChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.api.gameval.ItemID;
import net.runelite.api.gameval.SpotanimID;
import net.runelite.api.gameval.VarPlayerID;
import net.runelite.api.gameval.VarbitID;
import net.runelite.client.config.ConfigManager;
Expand Down Expand Up @@ -143,20 +145,12 @@ public enum AttackState
private static final int ATTACK_DELAY_NONE = 0;
public static final int DEFAULT_SIZE_UNIT_PX = 25;

public static final int SALAMANDER_SET_ANIM_ID = 952; // Used by all 4 types of salamander
// https://oldschool.runescape.wiki/w/Salamander

private static final int TWINFLAME_STAFF_WEAPON_ID = 30634;
private static final int ECHO_VENATOR_BOW_WEAPON_ID = 30434;
private static final int VENATOR_BOW_WEAPON_ID = 27610;
private static final int HALLOWFELL_ID = 34027; // https://oldschool.runescape.wiki/w/Hallowfell

// Add other weapons here if in the Runelite dev shell this prints a different value to it's actual speed:
//
// var itemManager = inject(ItemManager.class);
// log.info("Speed {}", itemManager.getItemStats(<id_to_test>).getEquipment().getAspeed());
private static final Map<Integer, Integer> NON_STANDARD_ATTACK_SPEEDS = new ImmutableMap.Builder<Integer, Integer>()
.put(HALLOWFELL_ID, 6)
.put(ItemID.HALLOWFELL, 6)
.build();

// These animations are the ones which exceed the duration of their attack cooldown
Expand All @@ -169,24 +163,21 @@ public enum AttackState
.build();

private static final Map<Integer, Integer> NON_STANDARD_MAGIC_WEAPON_SPEEDS = new ImmutableMap.Builder<Integer, Integer>()
.put(TWINFLAME_STAFF_WEAPON_ID, 6)
.put(ItemID.TWINFLAME_STAFF, 6)
.build();

// Map of problematic itemIds to equivalent working ones.
// The Echo Venator Bow's ItemStats are returning null, so use the regular bow instead.
private static final Map<Integer, Integer> WEAPON_ID_MAPPING_WORKAROUNDS = new ImmutableMap.Builder<Integer, Integer>().put(
ECHO_VENATOR_BOW_WEAPON_ID,
VENATOR_BOW_WEAPON_ID
).build();
private static final Map<Integer, Integer> WEAPON_ID_MAPPING_WORKAROUNDS = new ImmutableMap.Builder<Integer, Integer>()
.put(ItemID.VENATOR_BOW_ORNAMENT, ItemID.VENATOR_BOW)
.build();

// https://oldschool.runescape.wiki/w/Food/Fast_foods#Food_Delays
// These constants are not to be confused with eat delay.
private final int SLOW_FOOD_ATTACK_DELAY_TICKS = 4;
private final int DEFAULT_FOOD_ATTACK_DELAY_TICKS = 3;
private final int FAST_EAT_ATTACK_DELAY_TICKS = 2;

public static final int EQUIPPING_MONOTONIC = 384; // From empirical testing this clientint seems to always increase
// whenever the player equips an item
public static final Dimension DEFAULT_SIZE = new Dimension(DEFAULT_SIZE_UNIT_PX, DEFAULT_SIZE_UNIT_PX);

// region subscribers
Expand All @@ -205,8 +196,7 @@ public void onVarbitChanged(final VarbitChanged varbitChanged)
}

// onSoundEffectPlayed used to track spell casts, for when the player casts a spell on first tick coming
// off cooldown, in some cases (e.g. ice barrage) the player will have no animation. Also they don't have
// a projectile to detect instead :/
// off cooldown, in some cases (e.g. ice barrage) the player will have no animation.
@Subscribe
public void onSoundEffectPlayed(final SoundEffectPlayed event)
{
Expand Down Expand Up @@ -329,7 +319,7 @@ private ItemStats getWeaponStats(int weaponId)

private boolean getSalamanderAttack()
{
return client.getLocalPlayer().hasSpotAnim(SALAMANDER_SET_ANIM_ID);
return client.getLocalPlayer().hasSpotAnim(SpotanimID.FIREBREATH);
}

private void setAttackDelay()
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/attacktimer/AttackType.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public enum AttackType
STAB,
RANGED,
MAGIC,
NONE;
NONE,
;

public boolean IsMelee()
{
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/attacktimer/CastingSoundData.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ enum CastingSoundData
ARCEUUS_INFERIOR_DEMONBANE(5038, Spellbook.ARCEUUS),
ARCEUUS_SKELETAL_GRASP(5026, Spellbook.ARCEUUS),
ARCEUUS_SUPERIOR_DEMONBANE(5027, Spellbook.ARCEUUS),
ARCEUUS_UNDEAD_GRASP(5030, Spellbook.ARCEUUS);
ARCEUUS_UNDEAD_GRASP(5030, Spellbook.ARCEUUS),
;

private final int id;
private final Spellbook spellbook;
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/com/attacktimer/FontTypes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
package com.attacktimer;

/*
* Copyright (c) 2022, Nick Graves <https://github.com/ngraves95>
* 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 lombok.Getter;
import lombok.RequiredArgsConstructor;

Expand All @@ -14,7 +39,8 @@ public enum FontTypes
ROCKWELL("Rockwell"),
SEGOE_UI("Segoe Ui"),
TIMES_NEW_ROMAN("Times New Roman"),
VERDANA("Verdana");
VERDANA("Verdana"),
;

private final String name;

Expand Down
104 changes: 32 additions & 72 deletions src/main/java/com/attacktimer/PoweredStaves.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.attacktimer;

/*
* Copyright (c) 2024, Lexer747 <https://github.com/Lexer747>
* Copyright (c) 2024-2026, Lexer747 <https://github.com/Lexer747>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand All @@ -28,10 +28,10 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.Getter;
import net.runelite.api.gameval.ItemID;
import org.apache.commons.lang3.StringUtils;

// https://oldschool.runescape.wiki/w/Powered_staff
Expand All @@ -42,44 +42,35 @@
// 5. This Enum is only to contain the staves which allow magic at 4 ticks.
public enum PoweredStaves
{
WEAPON_ACCURSED( Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_ACCURSED_SCEPTRE_SPEC), Projectiles(2337, 2339), 27665, 27666), // https://oldschool.runescape.wiki/w/Accursed_sceptre
WEAPON_BLUE_C_STAFF_A(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1720), 23899), // https://oldschool.runescape.wiki/w/Crystal_staff_(attuned)
WEAPON_BLUE_C_STAFF_B(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1720), 23898), // https://oldschool.runescape.wiki/w/Crystal_staff_(basic)
WEAPON_BLUE_C_STAFF_P(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1720),23900), // https://oldschool.runescape.wiki/w/Crystal_staff_(perfected)
WEAPON_BONE_STAFF(AnimationData.MELEE_GENERIC_SLASH, Projectiles(2647), 28796, 28797), //https://oldschool.runescape.wiki/w/Bone_staff
WEAPON_DAWNBRINGER(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1544, 1547),22516), // https://oldschool.runescape.wiki/w/Dawnbringer
WEAPON_HARM(Set.of(
AnimationData.MAGIC_STANDARD_STRIKE_STAFF,
AnimationData.MAGIC_STANDARD_WAVE_STAFF,
AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF,
AnimationData.MAGIC_STANDARD_SURGE_STAFF
),
Projectiles(/*in level order then air -> fire*/
91, 94, 97, 100, /* strikes */
118, 121, 124, 127, /* bolts */
133, 136, 139, 130, /* blasts */
159, 162, 165, 156, /* waves */
1456, 1459, 1462, 1465 /* surges */),
24423), // https://oldschool.runescape.wiki/w/Harmonised_nightmare_staff
WEAPON_RED_C_STAFF_A(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1723), 23853), // https://oldschool.runescape.wiki/w/Corrupted_staff_(attuned)
WEAPON_RED_C_STAFF_B(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1723), 23852), // https://oldschool.runescape.wiki/w/Corrupted_staff_(basic)
WEAPON_RED_C_STAFF_P(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1723), 23854), // https://oldschool.runescape.wiki/w/Corrupted_staff_(perfected)
WEAPON_SANG(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1539), 22323), // https://oldschool.runescape.wiki/w/Sanguinesti_staff#Charged
WEAPON_SANG_KIT(AnimationData.MAGIC_STANDARD_WAVE_STAFF, 25731), // https://oldschool.runescape.wiki/w/Holy_sanguinesti_staff#Charged
WEAPON_STARTER_STAFF(22335, 22336, 28557, 28558), // https://oldschool.runescape.wiki/w/Starter_staff TODO get the animation when DMM goes live
WEAPON_SWAMP(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1040), 12899, 22292, 33314, 33318), // https://oldschool.runescape.wiki/w/Trident_of_the_swamp
WEAPON_THAMMARON(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(2340),22555, 22556), //https://oldschool.runescape.wiki/w/Thammaron%27s_sceptre
WEAPON_TRIDENT(AnimationData.MAGIC_STANDARD_WAVE_STAFF, Projectiles(1252), 11905, 11907, 22288, 33322, 33323, 33326), // https://oldschool.runescape.wiki/w/Trident_of_the_seas
WEAPON_WARPED_SCEPTRE(AnimationData.MAGIC_WARPED_SCEPTRE, 28585, 28586); // https://oldschool.runescape.wiki/w/Warped_sceptre
WEAPON_ACCURSED(Set.of(AnimationData.MAGIC_STANDARD_WAVE_STAFF, AnimationData.MAGIC_ACCURSED_SCEPTRE_SPEC), ItemID.WILD_CAVE_ACCURSED_CHARGED), // https://oldschool.runescape.wiki/w/Accursed_sceptre
WEAPON_BLUE_C_STAFF_A(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T2), // https://oldschool.runescape.wiki/w/Crystal_staff_(attuned)
WEAPON_BLUE_C_STAFF_B(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T1), // https://oldschool.runescape.wiki/w/Crystal_staff_(basic)
WEAPON_BLUE_C_STAFF_P(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T3), // https://oldschool.runescape.wiki/w/Crystal_staff_(perfected)
WEAPON_BONE_STAFF(AnimationData.MELEE_GENERIC_SLASH, ItemID.RAT_BONE_STAFF), // https://oldschool.runescape.wiki/w/Bone_staff
WEAPON_DAWNBRINGER(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.VERZIK_SPECIAL_WEAPON), // https://oldschool.runescape.wiki/w/Dawnbringer
WEAPON_HARM(
Set.of(AnimationData.MAGIC_STANDARD_STRIKE_STAFF, AnimationData.MAGIC_STANDARD_WAVE_STAFF,
AnimationData.MAGIC_STANDARD_STRIKE_BOLT_BLAST_STAFF, AnimationData.MAGIC_STANDARD_SURGE_STAFF),
ItemID.NIGHTMARE_STAFF_HARMONISED), // https://oldschool.runescape.wiki/w/Harmonised_nightmare_staff
WEAPON_RED_C_STAFF_A(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T2_HM), // https://oldschool.runescape.wiki/w/Corrupted_staff_(attuned)
WEAPON_RED_C_STAFF_B(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T1_HM), // https://oldschool.runescape.wiki/w/Corrupted_staff_(basic)
WEAPON_RED_C_STAFF_P(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.GAUNTLET_MAGIC_T3_HM), // https://oldschool.runescape.wiki/w/Corrupted_staff_(perfected)
WEAPON_SANG(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.SANGUINESTI_STAFF, ItemID.SANGUINESTI_STAFF_OR), // https://oldschool.runescape.wiki/w/Sanguinesti_staff#Charged
WEAPON_STARTER_STAFF(ItemID.DEADMAN_STARTER_STAFF, ItemID.DEADMAN_APOCALYPSE_STAFF), // https://oldschool.runescape.wiki/w/Starter_staff
WEAPON_SWAMP(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.TOXIC_TOTS_CHARGED, ItemID.TOXIC_TOTS_I_CHARGED,
ItemID.TOXIC_TOTS_CHARGED_ORN, ItemID.TOXIC_TOTS_I_CHARGED_ORN), // https://oldschool.runescape.wiki/w/Trident_of_the_swamp
WEAPON_THAMMARON(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.WILD_CAVE_SCEPTRE_CHARGED), // https://oldschool.runescape.wiki/w/Thammaron%27s_sceptre
WEAPON_TRIDENT(AnimationData.MAGIC_STANDARD_WAVE_STAFF, ItemID.TOTS, ItemID.TOTS_CHARGED, ItemID.TOTS_I_CHARGED,
ItemID.TOTS_CHARGED_ORN, ItemID.TOTS_ORN, ItemID.TOTS_I_CHARGED_ORN), // https://oldschool.runescape.wiki/w/Trident_of_the_seas
WEAPON_WARPED_SCEPTRE(AnimationData.MAGIC_WARPED_SCEPTRE, ItemID.WARPED_SCEPTRE), // https://oldschool.runescape.wiki/w/Warped_sceptre
;

@Getter
private final Set<Integer> ids;
@Getter
private final Set<Integer> projectiles;
@Getter
private final Set<AnimationData> animations;

private static Set<Integer> Projectiles(int... id)
private static Set<Integer> ListToSet(int... id)
{
ImmutableSet.Builder<Integer> builder = new ImmutableSet.Builder<>();
if (id.length == 0)
Expand All @@ -93,38 +84,27 @@ private static Set<Integer> Projectiles(int... id)
return builder.build();
}

// Unknown projectile and animation
// Unknown animation
PoweredStaves(int... id)
{
this.ids = Projectiles(id);
this.projectiles = null;
this.ids = ListToSet(id);
this.animations = null;
}

// Unknown projectile
// Single animation 4t powered staff
PoweredStaves(AnimationData spell, int... id)
{
this.ids = Projectiles(id);
this.projectiles = new HashSet<Integer>();
this.ids = ListToSet(id);
this.animations = Set.of(spell);
}

// Single animation 4t powered staff
PoweredStaves(AnimationData spell, Set<Integer> projectiles, int... id)
{
this.ids = Projectiles(id);
this.projectiles = projectiles;
this.animations = Set.of(spell);
}
// Multiple animations 4t powered staff
PoweredStaves(Set<AnimationData> spell, Set<Integer> projectiles, int... id)
PoweredStaves(Set<AnimationData> spell, int... id)
{
this.ids = Projectiles(id);
this.projectiles = projectiles;
this.ids = ListToSet(id);
this.animations = spell;
}

protected static final boolean LOCAL_DEBUGGING = false;
protected static final int UNKNOWN_SPELL = 0xDEADBEEF;
protected static final ImmutableMap<Integer, ImmutableMap<Integer, PoweredStaves>> POWERED_STAVES;

Expand All @@ -151,16 +131,6 @@ private static Set<Integer> Projectiles(int... id)
builder.put(id, spellMap.build());
}
}
if (LOCAL_DEBUGGING)
{
// Fake the kodai to be a harm for testing, because I don't own a harm.
ImmutableMap.Builder<Integer, PoweredStaves> spellMap = new ImmutableMap.Builder<>();
for (AnimationData harmAnim : WEAPON_HARM.animations)
{
spellMap.put(harmAnim.animationId, WEAPON_HARM);
}
builder.put(21006, spellMap.build());
}

POWERED_STAVES = builder.build();
}
Expand All @@ -185,18 +155,8 @@ public static PoweredStaves getPoweredStaves(int weaponId, AnimationData animati
public String toString()
{
String[] words = super.toString().toLowerCase().split("_");
Arrays.stream(words)
.map(StringUtils::capitalize).collect(Collectors.toList()).toArray(words);
Arrays.stream(words).map(StringUtils::capitalize).collect(Collectors.toList()).toArray(words);

return String.join(" ", words);
}

public boolean MatchesProjectile(int projectile)
{
if (this.projectiles == null)
{
return false;
}
return this.projectiles.contains(projectile);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/attacktimer/Spellbook.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public enum Spellbook
STANDARD(0),
ANCIENT(1),
LUNAR(2),
ARCEUUS(3);
ARCEUUS(3),
;

private final int id;

Expand Down
5 changes: 2 additions & 3 deletions src/main/java/com/attacktimer/VariableSpeed/BloodMoonSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@
import com.attacktimer.AttackProcedure;
import com.attacktimer.Spellbook;
import net.runelite.api.Client;
import net.runelite.api.gameval.SpotanimID;

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 atkType,
final Spellbook spellbook, final int damageDealt, final int lastSpecDelta, final int baseSpeed,
final int curSpeed)
{
if (client.getLocalPlayer().hasSpotAnim(BLOOD_MOON_SET_ANIM_ID))
if (client.getLocalPlayer().hasSpotAnim(SpotanimID.SPECIAL_DUAL_MACUAHUITL_SPOTANIM))
{
return curSpeed - 1;
}
Expand Down
Loading
Loading