fix(ui): retail target-cursor shape (pending over UI, world-object driven) + visible UseDone refusals

Visual gate round 2 (user, retail oracle): the target cursor over UI must
be the 0x27 four-arrows PENDING cursor — retail's UpdateCursorState
(0x00564630) keys valid/invalid solely off the SmartBox found object,
i.e. the WORLD entity under the cursor. And "can't heal myself" turned
out to be TWO stacked causes, both fixed:

- Cursor: UI hover no longer forces TargetInvalid (that arm was a
  non-retail invention) and the doll/status-bar hover providers are
  gone (UiElement.UseTargetGuidProvider deleted). Valid/invalid now
  come from (a) a hovered occupied item slot's own item, or (b) the
  world entity under the cursor via a new worldTargetProvider — the
  B.4b screen-rect picker extracted into GameWindow.PickWorldGuidAtCursor
  and shared by click + hover.
- Self-heal: the world picker always skipped the local player
  (skipServerGuid), so clicking your own toon in target mode could
  never acquire self. Target-use picks now include self (retail lets
  you kit-heal yourself by clicking your character); plain selection
  keeps the exclusion. The doll click still self-targets.
- Silent refusals: the [use-target] log proved the UseWithTarget action
  WAS sent (kit 0x00220008 / TargetType 0x10, target self) — ACE
  refused with WeenieError.YouArentTrainedInHealing (0x04FC) and we
  never parsed UseDone (0x01C7). Now dispatched + surfaced as a chat
  line via WeenieErrorText (interim subset map, register AP-74, #166
  ports the retail String-table lookup).

Full suite green (3,295).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-03 10:27:33 +02:00
parent 047410ccc9
commit 769ebef30d
10 changed files with 151 additions and 61 deletions

View file

@ -99,7 +99,6 @@ public sealed class PaperdollController : IItemListDragHandler
list.Cell.SourceKind = ItemDragSource.Equipment;
list.Cell.SlotIndex = i; // SlotMap position = this equipped item's drag-payload SourceSlot when dragged out to unwield
list.Cell.EmptySprite = emptySlotSprite; // visible empty-slot frame so every position is seen + usable. The live
list.Cell.UseTargetGuidProvider = _playerGuid;
list.Cell.Clicked = () => { _itemInteraction?.AcquireSelfTarget(); };
list.Cell.DoubleClicked = () =>
{
@ -125,15 +124,12 @@ public sealed class PaperdollController : IItemListDragHandler
if (layout.FindElement(id) is UiItemList armor) _armorSlots.Add(armor);
_dollViewport = layout.FindElement(0x100001D5u); // doll viewport (may be null until Slice 3)
if (_dollViewport is not null)
{
// The doll IS the player: hovering it during target-use resolves the
// valid/invalid cursor for SELF (retail: the SmartBox target is your
// own creature), and clicking it self-targets like the equip cells.
_dollViewport.UseTargetGuidProvider = _playerGuid;
if (_dollViewport is UiViewport doll)
doll.Clicked = () => { _itemInteraction?.AcquireSelfTarget(); };
}
// The doll IS the player: clicking it during target-use self-targets
// like the equip cells do. (The CURSOR over it stays the pending
// four-arrows — retail resolves target cursors off the SmartBox world
// object only; UI hover is always pending. 2026-07-03 visual gate.)
if (_dollViewport is UiViewport doll)
doll.Clicked = () => { _itemInteraction?.AcquireSelfTarget(); };
var slotsBtnEl = layout.FindElement(0x100005BEu);
if (slotsBtnEl is UiButton slotsBtn)

View file

@ -230,8 +230,6 @@ public sealed class ToolbarController : IItemListDragHandler
{
if (_inventoryButton is not null)
{
if (_itemInteraction is not null)
_inventoryButton.UseTargetGuidProvider = () => _itemInteraction.PlayerGuid;
_inventoryButton.OnClick = () =>
{
if (_itemInteraction?.AcquireSelfTarget() == true) return;