feat(ui): complete retail quick-slot input
Port global toolbar use/select/create actions, migrate the collapsed Ctrl-number bindings, and route them through a focused retained-UI controller. Preserve shortcut aliases as aliases across inventory and paperdoll drops with retail's neutral/accept/reject drag states, preventing physical item moves such as unwielding an equipped helmet. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
6fcc510d5d
commit
e65119f0c6
24 changed files with 650 additions and 69 deletions
|
|
@ -71,6 +71,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
private readonly Action<uint, uint>? _sendAddShortcut; // (index, objectGuid)
|
||||
private readonly Action<uint>? _sendRemoveShortcut; // (index)
|
||||
private readonly ItemInteractionController? _itemInteraction;
|
||||
private readonly Action<uint>? _selectItem;
|
||||
private bool _disposed;
|
||||
|
||||
// Digit sprite DID arrays for slot labels (top row, numbers 1-9).
|
||||
|
|
@ -98,7 +99,8 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
ItemInteractionController? itemInteraction = null,
|
||||
Action<uint, uint>? sendAddShortcut = null,
|
||||
Action<uint>? sendRemoveShortcut = null,
|
||||
Action? toggleCombat = null)
|
||||
Action? toggleCombat = null,
|
||||
Action<uint>? selectItem = null)
|
||||
{
|
||||
_repo = repo;
|
||||
_combatState = combatState;
|
||||
|
|
@ -111,6 +113,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
_itemInteraction = itemInteraction;
|
||||
_sendAddShortcut = sendAddShortcut;
|
||||
_sendRemoveShortcut = sendRemoveShortcut;
|
||||
_selectItem = selectItem;
|
||||
|
||||
for (int i = 0; i < SlotIds.Length; i++)
|
||||
{
|
||||
|
|
@ -233,11 +236,12 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
ItemInteractionController? itemInteraction = null,
|
||||
Action<uint, uint>? sendAddShortcut = null,
|
||||
Action<uint>? sendRemoveShortcut = null,
|
||||
Action? toggleCombat = null)
|
||||
Action? toggleCombat = null,
|
||||
Action<uint>? selectItem = null)
|
||||
{
|
||||
var c = new ToolbarController(layout, repo, shortcuts, iconIds, useItem, combatState,
|
||||
peaceDigits, warDigits, emptyDigits, itemInteraction,
|
||||
sendAddShortcut, sendRemoveShortcut, toggleCombat);
|
||||
sendAddShortcut, sendRemoveShortcut, toggleCombat, selectItem);
|
||||
c.Populate();
|
||||
return c;
|
||||
}
|
||||
|
|
@ -387,6 +391,95 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Port of <c>gmToolbarUI::UseShortcut @ 0x004BD350</c>. Target mode
|
||||
/// is one-shot and precedes both normal use and selection.
|
||||
/// </summary>
|
||||
public bool UseShortcut(int slot, bool use)
|
||||
{
|
||||
if ((uint)slot >= _slots.Length || _slots[slot]?.Cell is not { } cell)
|
||||
return false;
|
||||
|
||||
uint itemId = cell.ItemId;
|
||||
if (_itemInteraction?.IsTargetModeActive == true)
|
||||
{
|
||||
if (itemId != 0)
|
||||
_itemInteraction.OfferPrimaryClick(itemId);
|
||||
else
|
||||
_itemInteraction.CancelTargetMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemId == 0)
|
||||
return false;
|
||||
|
||||
if (use)
|
||||
{
|
||||
if (_itemInteraction is not null)
|
||||
_itemInteraction.ActivateItem(itemId);
|
||||
else
|
||||
_useItem(itemId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_selectItem?.Invoke(itemId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto-slot form of retail <c>gmToolbarUI::CreateShortcutToItem @
|
||||
/// 0x004BDAC0</c>, used by the global CreateShortcut action. It rejects
|
||||
/// stuck/non-player objects, non-player creatures, unowned objects,
|
||||
/// duplicates, and a full bar before emitting AddShortcut.
|
||||
/// </summary>
|
||||
public bool CreateShortcutToItem(uint itemId)
|
||||
{
|
||||
if (itemId == 0 || _repo.Get(itemId) is not { } item)
|
||||
return false;
|
||||
|
||||
var flags = (PublicWeenieFlags)(item.PublicWeenieBitfield ?? 0u);
|
||||
bool isPlayer = itemId == _itemInteraction?.PlayerGuid
|
||||
|| (flags & PublicWeenieFlags.Player) != 0;
|
||||
if ((flags & PublicWeenieFlags.Stuck) != 0 && !isPlayer)
|
||||
return false;
|
||||
if ((item.Type & ItemType.Creature) != 0 && !isPlayer)
|
||||
return false;
|
||||
if (_itemInteraction?.IsOwnedByPlayer(itemId) != true)
|
||||
return false;
|
||||
|
||||
EnsureStoreLoadedForMutation();
|
||||
for (int slot = 0; slot < _slots.Length; slot++)
|
||||
if (_store.Get(slot) == itemId)
|
||||
return false;
|
||||
|
||||
int empty = -1;
|
||||
for (int slot = 0; slot < _slots.Length; slot++)
|
||||
{
|
||||
if (_store.IsEmpty(slot))
|
||||
{
|
||||
empty = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (empty < 0)
|
||||
return false;
|
||||
|
||||
_store.Set(empty, itemId);
|
||||
_sendAddShortcut?.Invoke((uint)empty, itemId);
|
||||
Populate();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void EnsureStoreLoadedForMutation()
|
||||
{
|
||||
if (_storeLoaded)
|
||||
return;
|
||||
_store.Load(System.Linq.Enumerable.Select(_shortcuts(), e => ((int)e.Index, e.ObjectGuid)));
|
||||
_storeLoaded = true;
|
||||
}
|
||||
|
||||
// ── IItemListDragHandler (B.2 live handler) ──────────────────────────────
|
||||
// Retail: gmToolbarUI is the m_dragHandler for every shortcut slot list.
|
||||
// Retail model (remove-on-lift / place-on-drop / no-restore):
|
||||
|
|
@ -407,8 +500,8 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool OnDragOver(UiItemList targetList, UiItemSlot targetCell, ItemDragPayload payload)
|
||||
=> payload.ObjId != 0;
|
||||
public ItemDragAcceptance OnDragOver(UiItemList targetList, UiItemSlot targetCell, ItemDragPayload payload)
|
||||
=> payload.ObjId != 0 ? ItemDragAcceptance.Accept : ItemDragAcceptance.None;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void HandleDropRelease(UiItemList targetList, UiItemSlot targetCell, ItemDragPayload payload)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue