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

@ -54,15 +54,36 @@ public sealed class TargetIndicatorPanel
public float TriangleSize { get; set; } = 10f;
/// <summary>
/// World-space height of the indicator box. The panel projects feet
/// (at <c>WorldPosition</c>) and head (at <c>WorldPosition.Z +
/// EntityHeight</c>) to screen space and uses the projected pixel
/// distance as the box height. 1.8 m matches a standing humanoid;
/// World-space height of the indicator box for entities that don't
/// have a more specific type tag. Items use a smaller value (see
/// <see cref="EntityHeightFor"/>). 1.8 m matches a standing humanoid;
/// short items still get a small box because the projection
/// preserves apparent size.
/// </summary>
public float EntityHeight { get; set; } = 1.8f;
/// <summary>
/// Resolve the world-space height to use for a given entity's
/// indicator box. Humanoids (Creature flag) use 1.8 m; doors /
/// lifestones / portals use 2.4 m (door-frame tall); ground items
/// use 0.5 m so the box hugs the item rather than ballooning out
/// to humanoid height. Falls back to <see cref="EntityHeight"/>
/// for entities without a recognisable type tag.
/// </summary>
public float EntityHeightFor(uint itemType, uint pwdBitfield)
{
bool isCreature = (itemType & (uint)AcDream.Core.Items.ItemType.Creature) != 0;
if (isCreature) return 1.8f;
// BF_DOOR = 0x1000, BF_LIFESTONE = 0x4000, BF_PORTAL = 0x40000
// (acclient.h:6431-6463)
const uint TallStructureMask = 0x1000u | 0x4000u | 0x40000u;
if ((pwdBitfield & TallStructureMask) != 0) return 2.4f;
// Default: small ground item / object.
return 0.5f;
}
/// <summary>
/// Box width = <see cref="EntityHeight"/> projected height ×
/// <see cref="WidthHeightRatio"/>. Retail's Vivid Target Indicator
@ -111,10 +132,11 @@ public sealed class TargetIndicatorPanel
// projection.
if (!TryProjectToScreen(info.WorldPosition, viewProj, viewport, out var feetScreen))
return;
float entityHeight = EntityHeightFor(info.ItemType, info.ObjectDescriptionFlags);
var headWorld = new Vector3(
info.WorldPosition.X,
info.WorldPosition.Y,
info.WorldPosition.Z + EntityHeight);
info.WorldPosition.Z + entityHeight);
if (!TryProjectToScreen(headWorld, viewProj, viewport, out var headScreen))
return;