From a708a1f0b2bd57c61cf8a7ddd50a31e5adf2bd09 Mon Sep 17 00:00:00 2001 From: MagicBot Date: Thu, 15 Oct 2026 07:04:11 -0400 Subject: [PATCH] Use rune natural attack range for siege engines Siege engine range was hardcoded to 300. Read it from the rune natural attack instead (350 for Trebuchet, Mangonel and Ballista), matching the client's RecalcMinWeaponRange. Falls back to 300 if the rune has none. getNaturalAttack now returns the whole entry so speed and range share the lookup. Co-Authored-By: Claude Opus 5.5 --- src/engine/gameManager/CombatManager.java | 46 ++++++++++++++++++++--- src/engine/objects/AbstractCharacter.java | 2 +- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/engine/gameManager/CombatManager.java b/src/engine/gameManager/CombatManager.java index c7f267ca..23043bcd 100644 --- a/src/engine/gameManager/CombatManager.java +++ b/src/engine/gameManager/CombatManager.java @@ -151,7 +151,7 @@ public enum CombatManager { if (attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) if (((Mob) attacker).isSiege()) - attackRange = 300; + attackRange = getSiegeRange((Mob) attacker); float distanceSquared = attacker.loc.distanceSquared(target.loc); @@ -665,6 +665,42 @@ public enum CombatManager { public static float getNaturalAttackSpeed(AbstractCharacter attacker, mbEnums.EquipSlotType slot) { // Returns the rune natural attack speed (x100 ms) for this hand, or 0 if the rune has none. + + float[] attack = getNaturalAttack(attacker, slot); + + if (attack == null || attack.length < 1) + return 0; + + return attack[0]; + } + + public static float getNaturalAttackRange(AbstractCharacter attacker, mbEnums.EquipSlotType slot) { + + // Returns the rune natural attack range for this hand, or 0 if the rune has none. + + float[] attack = getNaturalAttack(attacker, slot); + + if (attack == null || attack.length < 2) + return 0; + + return attack[1]; + } + + public static float getSiegeRange(Mob siegeEngine) { + + // Siege engines use the range from their rune natural attack (350 for all three), 300 if the rune has none. + + float range = getNaturalAttackRange(siegeEngine, mbEnums.EquipSlotType.RHELD); + + if (range <= 0) + return 300; + + return range; + } + + public static float[] getNaturalAttack(AbstractCharacter attacker, mbEnums.EquipSlotType slot) { + + // Returns the rune natural attack entry for this hand, or null if the rune has none. // Mobs use their mobbase rune, players use their race rune. int runeID; @@ -679,21 +715,21 @@ public enum CombatManager { runeID = ((PlayerCharacter) attacker).getRaceID(); break; default: - return 0; + return null; } rune = ItemTemplate.templates.get(runeID); if (rune == null || rune.rune_natural_attacks.isEmpty()) - return 0; + return null; for (float[] attack : rune.rune_natural_attacks) if (attack.length > 3 && (int) attack[3] == hand) - return attack[0]; + return attack; // No entry for this hand, fall back to the first natural attack - return rune.rune_natural_attacks.get(0)[0]; + return rune.rune_natural_attacks.get(0); } public static int calculatePetDamage(AbstractCharacter agent) { diff --git a/src/engine/objects/AbstractCharacter.java b/src/engine/objects/AbstractCharacter.java index e2e41f64..eb31e338 100644 --- a/src/engine/objects/AbstractCharacter.java +++ b/src/engine/objects/AbstractCharacter.java @@ -1476,7 +1476,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject { Mob mob = (Mob) this; if (mob.isSiege()) { - return 300; + return CombatManager.getSiegeRange(mob); } float range = 8; if ((this).charItemManager.equipped.get(EquipSlotType.RHELD) != null) {