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.
Visual test surfaced three follow-ups:
1. Square box, not 1:2 rectangle.
WidthHeightRatio: 0.5 → 1.0. Retail's Vivid Target Indicator draws
a square; the earlier humanoid-aspect ratio looked wrong for
non-humanoids and didn't match retail screenshots.
2. Large flat objects (doors / lifestones / portals / corpses)
weren't selectable with the new tight 0.7 m pick sphere.
WorldPicker.Pick now takes an optional radiusForGuid callback so
the host can per-entity decide a larger radius. GameWindow's pick
site supplies a lambda that bumps to 2.0 m for any entity with
BF_DOOR (0x1000), BF_LIFESTONE (0x4000), BF_PORTAL (0x40000), or
BF_CORPSE (0x2000) set in ObjectDescriptionFlags. Default stays
at 0.7 m for humanoids and items.
3. New [B.7] pick-info diagnostic on each successful pick:
[B.7] pick-info guid=0x... itemType=0x... pwd=0x... color=(r,g,b)
Lets us verify e.g. whether a 'green NPC' really is server-side
flagged as Vendor (BF_VENDOR=0x200, retail-defined green) vs a
bug in our colour lookup. The pwd bit table is acclient.h:6431-
6463 — same flags retail's gmRadarUI::GetBlipColor branches on.
Note: textured retail-sprite corner triangles remain a B.7 follow-up
deferred per the spec. MVP uses procedural fills.
Visual test surfaced two B.7 MVP issues:
1. Box anchored at abdomen + fixed 48px size meant the rectangle
shrank visually as the camera approached the entity (entity got
bigger on screen, box stayed 48px → triangles ended up inside
the silhouette).
2. Origin was a single point (entity position + 0.9m WorldVerticalOffset)
so the box wasn't centred on the visible body.
Fix: project both feet (WorldPosition) and head (WorldPosition.Z +
EntityHeight=1.8m) to screen space. Apparent pixel height between the
two = box height; halve it for width (WidthHeightRatio=0.5 ≈
humanoid). Box centred at midpoint of projected feet+head.
- Closer entity → bigger projected height → bigger box. Distance
scaling is automatic from the perspective projection.
- Farther entity → smaller projected height → MinScreenHeight=16px
floor prevents the box collapsing to a point.
- Box is screen-axis-aligned (always rectangular on screen) but
sized + positioned by the entity's actual world-space silhouette.
Properties exposed (TriangleSize, EntityHeight, WidthHeightRatio,
MinScreenHeight) so the panel can be tuned per-instance if a future
caller wants short-item boxes (drop EntityHeight to ~0.3m for tapers,
keep WidthHeightRatio at 1.0 for a square box).
Stuck-on-+Je issue (clicking other things still returns +Je) is
Issue #59 — picker over-pick — and unaffected by this commit.
Per the B.7 design spec, wires a Vivid-Target-Indicator-style overlay
into GameWindow's ImGui pass:
TargetIndicatorPanel (src/AcDream.App/UI/TargetIndicatorPanel.cs)
- Three delegates injected from GameWindow:
selectedGuidProvider -> _selectedGuid
entityResolver -> (worldPos, itemType, pwdBits) from
_entitiesByServerGuid + _liveEntityInfoByGuid
+ _lastSpawnByGuid
cameraProvider -> (view, projection, viewport) from
_cameraController.Active + _window.Size
- Per-frame Render():
* Bail on null selection / despawned entity / zero viewport.
* Project entity world position (+0.9m mid-body offset) to NDC.
* Bail off-screen (no edge arrow in MVP).
* Convert to viewport pixel coords, draw 4 right-angle triangles
at corners of a 48px square around the projected center.
* Colour from RadarBlipColors.For(itemType, pwdBits).
GameWindow wiring:
- Construct _targetIndicator right after _panelHost during ImGui init.
- Call _targetIndicator?.Render() between _panelHost.RenderAll and
_imguiBootstrap.Render — draws to the ImGui background list so
docked panels can occlude the indicator if they overlap.
Build green. Core.Tests went 1046 -> 1054 (+8 RadarBlipColors tests
from the prior commit). Baseline failures unchanged at 8.
Visual verification next: launch, click an NPC → yellow corners; click
an item -> white corners; deselect -> corners disappear.