Creatures now run two clocks: the think clock (ActiveSpeed/PassiveSpeed,
seconds per decision - unchanged in meaning, storage, and cadence) and a new
movement clock (ActiveMoveSpeed/PassiveMoveSpeed, seconds per step, 0 =
inherit the matching think value). This lets movement pace be tuned freely -
e.g. toward RunUO's TransformMoveDelay pacing - without touching reaction
time, spell timing, or acquisition cadence.
- BaseCreature: move-speed pair seeded from npc-speeds.json (optional
activeMove/passiveMove per bucket), [props-tunable per instance (0 to
re-inherit), serialized (v22). SetSpeed keeps its legacy one-clock
semantics: it sets the think clock AND clears move overrides, so existing
callers cannot half-configure a creature; SetMoveSpeed/ClearMoveSpeed
configure movement explicitly. CurrentMoveSpeed resolves by classifying
CurrentSpeed - a verbatim active/passive value maps to the matching move
value, while bespoke paces written directly (mount boosts, follow sprint)
stay fused to both clocks, so external CurrentSpeed writers keep working
untouched.
- Movement budget: one step consumes a full step of movement-clock budget,
accumulative with RunUO's snap-to-now clamp, so long-run pacing averages
CurrentMoveSpeed exactly and a stall banks at most one step of catch-up.
- AITimer: dual-deadline scheduling. Decisions run at the think cadence
exactly as before; while a pursuit or investigation is live, the timer also
wakes when the movement budget elapses and advances the step without
running decisions. Steps no longer snap to the think grid, so any step
delay paces smoothly on the 8ms timer wheel - no ping-pong stutter from
incommensurate values. A blocked creature schedules no move wakes and
stays think-paced.
- Move intent: ApproachTarget/MoveToPoint record their durable goal each
en-route tick; arrival, failure, give-up, action changes, or missed
renewals clear it.
- Badly-hurt slowdown now inflates the step delay only (RunUO parity) and is
computed from the base each step. Previously it wrote CurrentSpeed back
onto itself, compounding unboundedly while hurt and slowing decisions too.
No behavior changes by default: with no bucket or per-instance move values,
both clocks carry identical values and creatures pace as before.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>