Conversation
GregHib
left a comment
There was a problem hiding this comment.
Thanks for the contribution! Admittedly this does need a proper architecture solution but this will be a nice short term fix
Thanks for your feed back, I moved step-out logic from CombatMovement into Movement. Since "step out from under a character target" is a movement concern rather than a combat concern, the logic was moved to Movement (the base class) where it applies to all modes automatically. The shape == -2 guard scopes it to character targets only, and the shouldQueueStepOut() hook lets CombatMovement skip queuing a random step when both characters are already in active combat movement, clearing the stale steps and letting normal recalculation take over instead. |
|
These bug fixes are included on the castle wars feature PR: #948 |
| updateRange = false | ||
| val target = target | ||
| val npc = character as? NPC | ||
| if (npc != null && !npc.def["allowed_under", false] && target is Character && |
Bug Fix: NPCs spawned under a target couldn't attack
Summary
NPCs spawned under a target couldn't attack because Interact mode (used for the initial attack interaction) had no logic to step out from under the target, unlike
CombatMovementwhich explicitly handles this case.Root Cause
When an NPC with
allowed_under = falseis on the same tile as its target, the following chain of failures occurs:Movement.arrived()false(overlap check fails)calculate()super.tick()cantReach()Fix
Interact.kt(tick()): Before the normalcalculate()/processInteraction()flow, check if the NPC is under its target and not allowed there. If so, mirrorCombatMovement.stepOut()behavior:super.tick()to execute the stepThis lets the NPC move out from under the target on the first tick, allowing combat to initialize normally on the second tick.
Test
CombatMovementTest.kt: Creates a guard NPC spawned at the same tile as a player, callsinteractPlayer(player, "Attack"), ticks twice, and verifies the NPC has moved away and transitioned toCombatMovement.Demo
Screencast_20260410_061246.webm
Bug Fix: Character creation screen skipped for new accounts
Summary
New accounts were not shown the
character_creationinterface on first login.Root Cause
AccountManager.create()was setting the"creation"timestamp immediately when a new player record was created.Introduction.welcome()uses the presence of"creation"to detect returning players and skip the screen, so new accounts were being mistaken for returning players before they ever logged in.Fix
Removed
"creation"fromAccountManager.create(). The timestamp is already set byIntroduction.setup()after thecharacter_creationinterface closes, which is the correct point in time. Updated the corresponding test to no longer assert the premature value.Bug Fix: Dragon claws special attack damage and hit timing
Summary
Fixes the dragon claws "Slice and Dice" special attack (
DragonClaws.kt) to match the 2011 behavior. There were three damage formula bugs and a fundamental engine-level timing issue causing all four hits to land on the same tick.Damage Formula Fixes
maxHit - 10maxHit - 1(i.e.nextInt(maxHit/2, maxHit))hit3 + random(0, 10)hit3 + 1, confirmed by documented examples (35-17-8-9,0-30-15-16,0-0-22-23)0or10per hit0-0-0-0Hit Timing Fix
All four hitsplats were landing on the same tick. The spec requires two pairs: hits 1 & 2 on the activation tick, hits 3 & 4 on the following tick (0.6 seconds later).
Root cause:
ActionQueue.tick()runs awhile (queue.isNotEmpty())loop that callsremoveIfrepeatedly, decrementingremainingon every pass. This fast-forwards any delayed actions within the same tick, soinitialDelay = 2would get decremented to 0 over two passes in a singlequeue.tick()call, regardless of the delay value passed tohit().Fix: Instead of passing a delay to the final two
hit()calls, hits 3 and 4 are now dispatched from inside astrongQueueproxy action on the target. BecausestrongQueueadds topending(notqueue), andqueuePending()only runs at the start of the nextqueue.tick(), anything added topendingduring an activequeue.tick()is naturally deferred by one full tick, with no delay arithmetic needed.