Files
healer-man/docs/ENEMY_FEAR_MOVEMENT_2026-10-06.md
2026-10-06 22:25:34 -04:00

8.2 KiB
Raw Permalink Blame History

Enemy fear movement follow-up — 2026-10-06

This pass integrates source-informed movement for the pinned enemy shout fear auras into player, party and mobile owned-summon consumers. Voluntary movement, jumping, attacks and casts remain suppressed while fear controls the actor. Movement requires reviewed navigation and collision/LOS approval. Missing or blocked spatial support safely holds the actor. Other controls retain their existing policy; this does not claim exact historical-server path or RNG parity.

Historical core behavior

The read-only historical source is AzerothCore commit e822d718322289dd036fb2daf8867ba41283bf9a, specifically src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp, src/server/game/Movement/MotionMaster.cpp, src/server/game/Entities/Unit/Unit.cpp, and src/server/game/Spells/Auras/SpellAuraEffects.cpp under ../wow-pvt-server-backups-2/azerothcore-wotlk.

HandleModFear passes the live aura caster to Unit::SetControlled; that passes it to SetFeared, then MotionMaster::MoveFleeing. The generator looks up the caster GUID when it chooses each new destination. It does not preserve the caster's cast-time position. If that lookup fails, it picks a random angle and follows its near-source distance branch with a source distance of zero. A dead caster can still resolve while its unit remains in-world; after removal, the source-less fallback applies.

The source's exact movement bounds and retries are:

Core rule Source value
Quiet-range lower bound 28 yd
Quiet-range upper bound 43 yd
Minimum accepted path 2 yd
Path length limit 30 yd
Retry after destination LOS failure 200 ms
Retry after failed, short, or invalid path 100 ms
Repath wait after spline travel random 800–1500 ms

Below 28 yards, the server picks a distance between 0.4 and 1.3 times the remaining distance to 28 yards and a heading within ±π/8 of the direction away from the source. Above 43 yards, it picks 0.4–1.0 times the 15-yard band width and heads partly back toward the source, within ±π/4. Inside the quiet band, it picks 0.6–1.2 times the band width in a random direction. A source distance at or below 0.2 yards uses a random base angle. The core constrains the candidate with MovePositionToFirstCollision, checks LOS to the resulting point, then asks PathGenerator for a path and rejects shortcuts, no-path, far-from-poly, paths shorter than 2 yards, and paths beyond the 30-yard limit. After five failed paths it stops looking up the source and uses the source-less random fallback.

SetControlled does not start fear while stun or confusion already owns the unit. When the higher-priority control ends, it rechecks active fear auras and resolves their caster GUID. This helper accepts the actor's active stun end time and holds fear movement until that higher-priority control expires.

Planner boundary

src/game/enemyFearMovement.ts carries the source distance bands, steering ranges, LOS/path retries, and path length limits. Its hash-based choices are simulator decisions: they reproduce the source's ranges with stable values derived from actor ID, source ID, aura application time, and decision index. They do not reproduce the core's global random-number stream. worldUnitsPerYard is required input because imported map coordinates can have a different scale. The estimated time to the next choice uses approved path length divided by this actor's current effective speed, then adds a seeded wait from the core's 800–1500 ms range.

Each actor supplies its own fear expiry, stun expiry, base movement speed, and source speed multiplier. The shout's +25% speed is therefore applied only when that target has the still-active source speed aura. The current adapters are limited to tagged source fear. getSourcePosition runs once per repath so the goal uses the live caster location at that decision; the caller should cache the resulting goal until nextDecisionAtMs instead of recomputing it every frame.

The planner requires three map adapters: a projection that rejects excessive snaps and floor changes, an LOS test, and a complete actor-safe path-length query. Missing map support, an unsafe projection, blocked LOS, or an invalid route yields a hold with the source retry timing. The destination is a route goal only. The caller must move through actor collision and approved navigation waypoints; it must never assign the destination directly to an actor position. stepEnemyFearTowardDestination only computes a bounded request and does not replace those checks.

Integration seams before this pass

  • PlayerRig resolves the player's shout control near its frame movement step. enemyControlPreventsMovement currently blocks all fear before movement, and Rapier's character controller checks the player's capsule against terrain. For a tagged source fear with no active stun, the frame can use the cached flee goal to set the autonomous world movement vector, then submit its bounded delta through the existing character controller. The goal must not be derived from camera input or change camera yaw.
  • PartyPopulation similarly blocks fear before companion route planning. It already has the reviewed navigation graph, planPartyRoute, direct-segment collision checks, and route-segment clearance validation. A fear goal should use those route helpers and hold when no safe route exists.
  • The summon loop in combatStore.ts returns early when controlledUntil is active, before movement and actions. CombatSummon currently keeps a control expiry but no control mechanic. A source fear adapter needs to preserve the per-summon fear and stun state, move only when fear is the active control, and continue to suppress actions. CombatSpatialProvider provides live actor positions, LOS, ground projection, and the reviewed navigation graph; the adapter still needs to validate a complete route before advancing a summon.
  • The shout control resolver currently returns only mechanic and expiry. The integration must identify the active tagged ActiveAura per actor to retain its source ID and appliedAt for live source lookup and deterministic seeding. That lookup can use the mob runtime position while the caster exists; when the source ID no longer resolves, pass null and use the source-less branch.

The existing hostile NPC fear path is separate. MobPopulation already calls stepFearedMobAway and clamps that direct step to the home leash, using the current aggro target as the threat. That helper does not perform LOS or route validation for the flee step. This follow-up leaves it unchanged and does not claim it matches the historical generator.

Integrated consumers and verification

enemyFearMovementRuntime.ts retains the selected aura's source/application, caches each goal and implements the five-failure source fallback. Concurrent tagged stun and generic stun/confuse/root/sleep auras hold movement even when the actor's longest control timer belongs to fear. Expiry or purge clears the per-actor goal; a refreshed aura starts a new decision sequence.

PlayerRig follows approved route waypoints through its existing Rapier character controller, including gravity. Keyboard movement and jumping do not steer fear. PartyPopulation uses its reviewed graph and capsule route validators, normal party speed with actor-local source modifiers, and follows forced fear even under Stop. Fear never enables catch-up speed or stuck-recovery relocation. Camera look retains its ordinary hold-and-drag behavior.

enemyFearSummonMovement.ts requires a loaded graph and validates projection, LOS, path segments and each bounded step. The actual combat tick consumes it before summon actions, holds concurrent controls, and preserves the pet's Prowl movement modifier. Totems and stationary zones remain stationary. Remote actor authority and hostile-NPC flee policy remain outside this bounded integration.

Focused planner/cache/summon verification passes 20 tests, including actual pet ticks, blocked/missing navigation and simultaneous stun expiry. Input regressions pass 33 tests. Final build/live evidence is recorded in the combined follow-up report.