fix(B.7): square indicator box + bigger pick sphere for doors/lifestones/portals + diag

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.
This commit is contained in:
Erik 2026-05-15 07:13:23 +02:00
parent 631571a6ef
commit 23cb1e9636
3 changed files with 51 additions and 8 deletions

View file

@ -8991,13 +8991,47 @@ public sealed class GameWindow : IDisposable
origin, direction,
_entitiesByServerGuid.Values,
skipServerGuid: _playerServerGuid,
maxDistance: 50f);
maxDistance: 50f,
// B.7 (2026-05-15): widen the pick sphere for large flat
// objects (doors, lifestones, portals, corpses) so their
// visible surface stays clickable even though the entity
// origin is a single point. 0.7 m default is fine for
// humanoids and most items; doors / portals need ~2 m
// to cover the doorframe.
radiusForGuid: g =>
{
if (_lastSpawnByGuid.TryGetValue(g, out var s)
&& s.ObjectDescriptionFlags is { } odf)
{
// BF_DOOR = 0x1000, BF_LIFESTONE = 0x4000,
// BF_PORTAL = 0x40000, BF_CORPSE = 0x2000
// (acclient.h:6431-6463)
const uint LargeFlatMask = 0x1000u | 0x4000u | 0x40000u | 0x2000u;
if ((odf & LargeFlatMask) != 0) return 2.0f;
}
return 0.7f;
});
if (picked is uint guid)
{
_selectedGuid = guid;
string label = DescribeLiveEntity(guid);
Console.WriteLine($"[B.4b] pick guid=0x{guid:X8} name={label}");
// B.7 (2026-05-15): one-shot per-pick diagnostic so we can
// see exactly which ItemType + PWD bitfield bits + resolved
// RadarBlipColor are produced for the just-picked entity.
// Helps verify whether a "green NPC" really is flagged as
// Vendor server-side or whether our lookup is wrong.
uint rawItemType = 0;
if (_liveEntityInfoByGuid.TryGetValue(guid, out var info))
rawItemType = (uint)info.ItemType;
uint pwdBits = 0;
if (_lastSpawnByGuid.TryGetValue(guid, out var spawn)
&& spawn.ObjectDescriptionFlags is { } odf)
pwdBits = odf;
var col = AcDream.Core.Ui.RadarBlipColors.For(rawItemType, pwdBits);
Console.WriteLine(System.FormattableString.Invariant(
$"[B.7] pick-info guid=0x{guid:X8} itemType=0x{rawItemType:X8} pwd=0x{pwdBits:X8} color=({col.R},{col.G},{col.B})"));
_debugVm?.AddToast($"Selected: {label}");
if (useImmediately) SendUse(guid);
}