fix(B.6+B.7): run-all-the-way auto-walk, per-type indicator height, R = smart interact

Three user-reported fixes:

1. (B.6) Run-vs-walk decision lifted out of the per-frame overlay
   into BeginServerAutoWalk. Once set at auto-walk start, the
   character runs (or walks) the full way to the target instead of
   transitioning. Matches user-observed retail behaviour:
   'if its far away it should run all the way to the object and
   then stop'.
   _autoWalkWalkRunThreshold → _autoWalkInitiallyRunning (bool,
   sampled once from initial distance vs the wire's WalkRunThreshold).

2. (B.7) TargetIndicatorPanel now picks EntityHeight per-type:
     Creature (NPC/player)                          → 1.8 m
     Door / Lifestone / Portal (tall structures)    → 2.4 m
     Default (small ground item)                    → 0.5 m
   Items now get a small box hugging the silhouette instead of a
   humanoid-tall rectangle floating around them.

3. (Interact) R-key (UseCurrentSelection) now dispatches by target
   type:
     Item (no Creature flag, no BF_DOOR|LIFESTONE|PORTAL|CORPSE)
       → SendPickUp (PutItemInContainer 0x0019)
     Everything else  → SendUse (0x0036)
   Single hotkey to interact with whatever's selected.

Deferred (separate phase): turn-to-face on close-range use. ACE
server-side does Rotate(target) before the close-range pickup
callback (Player_Move.cs:71), but our local body doesn't echo
the turn yet — needs a synthesized client-side rotation or
MovementType=8 TurnToObject handling. Filing as follow-up.
This commit is contained in:
Erik 2026-05-15 07:35:38 +02:00
parent 1a0656a3ce
commit 211fe240b8
3 changed files with 82 additions and 24 deletions

View file

@ -234,12 +234,13 @@ public sealed class PlayerMovementController
private float _autoWalkMinDistance;
private float _autoWalkDistanceToObject;
private bool _autoWalkMoveTowards;
// Wire's WalkRunThreshold — retail semantic: locomotion runs while
// remaining distance > threshold, walks once inside threshold. ACE's
// Use/PickUp path uses MoveToParameters.SetDefaults() = 15.0f, so
// most pickup targets walk the entire way. ACE's charge path sets
// it to 1.0f so combat chase runs almost the whole way.
private float _autoWalkWalkRunThreshold;
// Walk-vs-run decision is made ONCE at BeginServerAutoWalk based on
// initial distance vs the wire's WalkRunThreshold, then held for the
// duration of the auto-walk. Earlier per-frame evaluation produced
// "runs partway then walks the rest" which the user reported as
// wrong: the character should run all the way to the target then
// stop, not transition to a walk near the end.
private bool _autoWalkInitiallyRunning;
/// <summary>
/// True while a server-initiated auto-walk (MoveToObject inbound) is
@ -357,7 +358,18 @@ public sealed class PlayerMovementController
_autoWalkMinDistance = minDistance;
_autoWalkDistanceToObject = distanceToObject;
_autoWalkMoveTowards = moveTowards;
_autoWalkWalkRunThreshold = walkRunThreshold;
// Decide run vs walk ONCE based on the initial horizontal
// distance from the player to the destination. Run-all-the-way
// is the retail-faithful behaviour the user observed: pick a
// distant target → character runs the whole way, decelerates
// to a stop at use radius. Earlier per-frame evaluation made
// the body transition to a walk inside threshold and felt
// wrong (the user reported "runs partway then walks").
float dx = destinationWorld.X - _body.Position.X;
float dy = destinationWorld.Y - _body.Position.Y;
float initialDist = MathF.Sqrt(dx * dx + dy * dy);
_autoWalkInitiallyRunning = initialDist > walkRunThreshold;
}
/// <summary>
@ -452,15 +464,13 @@ public sealed class PlayerMovementController
while (Yaw < -MathF.PI) Yaw += 2f * MathF.PI;
}
// Walk vs run per the wire's WalkRunThreshold. Retail semantics:
// dist > threshold → RUN, dist ≤ threshold → WALK. ACE's default
// for Use/PickUp is 15.0 m (so close targets walk the whole way);
// ACE's combat charge path sets it to 1.0 m (so chase runs to the
// last metre then walks the final approach). Matches the user's
// observed retail behaviour: "When at a distance X it should
// start running towards the double clicked target… When at a
// shorter distance it should walk to it."
bool shouldRun = dist > _autoWalkWalkRunThreshold;
// Walk vs run decided ONCE at BeginServerAutoWalk based on
// initial distance — held for the rest of the auto-walk so the
// character keeps running all the way to the target instead of
// transitioning to a walk inside the threshold. Matches user-
// observed retail behaviour ("if its far away it should run
// all the way to the object and then stop").
bool shouldRun = _autoWalkInitiallyRunning;
// Synthesize "moving forward" input. The rest of Update reads
// Yaw + input.Forward + input.Run to drive _motion + body