feat(ui): port retail toolbar ammo count
Resolve stacked thrown weapons versus separately equipped missile ammo exactly like gmToolbarUI, normalize a zero stack to one, and refresh the authored missile indicator from equipment and stack events. Keep the decision in pure Core with retained and real-DAT conformance coverage. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
400f01eef1
commit
564d39dfea
9 changed files with 330 additions and 7 deletions
|
|
@ -48,6 +48,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
private const uint PanelIdAttribute = 0x10000029u;
|
||||
private const uint UseButtonId = 0x1000019Du;
|
||||
private const uint ExamineButtonId = 0x100001A5u;
|
||||
private const uint AmmoIndicatorId = 0x10000194u;
|
||||
private const uint InventoryButtonId = 0x100001B1u;
|
||||
private static readonly uint[] PanelButtonIds =
|
||||
{ 0x10000197u, 0x10000198u, 0x10000199u, 0x1000055Au, 0x1000019Au, 0x1000019Bu, InventoryButtonId };
|
||||
|
|
@ -57,6 +58,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
private readonly UiButton? _inventoryButton;
|
||||
private readonly UiButton? _useButton;
|
||||
private readonly UiButton? _examineButton;
|
||||
private readonly UiButton? _ammoIndicator;
|
||||
private readonly List<(uint PanelId, UiButton Button)> _panelButtons = new();
|
||||
private readonly ClientObjectTable _repo;
|
||||
private readonly CombatState? _combatState;
|
||||
|
|
@ -72,6 +74,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
private readonly Func<uint> _selectedObjectId;
|
||||
private readonly Func<uint>? _playerGuid;
|
||||
private readonly Action<uint, uint, int>? _sendPutItemInContainer;
|
||||
private uint _ammoObjectId;
|
||||
private bool _disposed;
|
||||
|
||||
// Digit sprite DID arrays for slot labels (top row, numbers 1-9).
|
||||
|
|
@ -103,7 +106,8 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
Action<uint>? selectItem = null,
|
||||
Func<uint>? selectedObjectId = null,
|
||||
Func<uint>? playerGuid = null,
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null)
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null,
|
||||
UiDatFont? ammoFont = null)
|
||||
{
|
||||
_repo = repo;
|
||||
_combatState = combatState;
|
||||
|
|
@ -149,6 +153,13 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
button.OnClick = toggleCombat;
|
||||
}
|
||||
|
||||
_ammoIndicator = layout.FindElement(AmmoIndicatorId) as UiButton;
|
||||
if (_ammoIndicator is not null)
|
||||
{
|
||||
_ammoIndicator.LabelFont = ammoFont;
|
||||
_ammoIndicator.LabelColor = System.Numerics.Vector4.One;
|
||||
}
|
||||
|
||||
foreach (uint elementId in PanelButtonIds)
|
||||
{
|
||||
if (layout.FindElement(elementId) is UiButton panelButton
|
||||
|
|
@ -189,14 +200,60 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
repo.ObjectAdded += OnRepositoryObjectChanged;
|
||||
repo.ObjectUpdated += OnRepositoryObjectChanged;
|
||||
repo.ObjectRemoved += OnRepositoryObjectChanged;
|
||||
repo.ObjectMoved += OnRepositoryObjectMoved;
|
||||
RefreshAmmo();
|
||||
}
|
||||
|
||||
private void OnRepositoryObjectChanged(ClientObject obj)
|
||||
{
|
||||
if (IsAmmoRelated(obj))
|
||||
RefreshAmmo();
|
||||
if (IsShortcutGuid(obj.ObjectId))
|
||||
Populate();
|
||||
}
|
||||
|
||||
private void OnRepositoryObjectMoved(ClientObject obj, uint oldContainer, uint newContainer)
|
||||
{
|
||||
uint player = _playerGuid?.Invoke() ?? 0u;
|
||||
if (obj.ObjectId == _ammoObjectId
|
||||
|| (player != 0 && (oldContainer == player || newContainer == player)))
|
||||
RefreshAmmo();
|
||||
if (IsShortcutGuid(obj.ObjectId))
|
||||
Populate();
|
||||
}
|
||||
|
||||
private bool IsAmmoRelated(ClientObject obj)
|
||||
{
|
||||
uint player = _playerGuid?.Invoke() ?? 0u;
|
||||
return obj.ObjectId == _ammoObjectId
|
||||
|| (player != 0 && obj.ObjectId == player)
|
||||
|| (player != 0
|
||||
&& obj.ContainerId == player
|
||||
&& (obj.CurrentlyEquippedLocation
|
||||
& (EquipMask.MissileWeapon | EquipMask.MissileAmmo)) != 0);
|
||||
}
|
||||
|
||||
private void RefreshAmmo()
|
||||
{
|
||||
uint player = _playerGuid?.Invoke() ?? 0u;
|
||||
var placements = new List<ClientObject>();
|
||||
if (player != 0)
|
||||
{
|
||||
foreach (uint objectId in _repo.GetContents(player))
|
||||
if (_repo.Get(objectId) is { } item)
|
||||
placements.Add(item);
|
||||
}
|
||||
|
||||
ToolbarAmmoPolicy.Result result = ToolbarAmmoPolicy.Resolve(placements);
|
||||
_ammoObjectId = result.ObjectId;
|
||||
if (_ammoIndicator is not null)
|
||||
{
|
||||
_ammoIndicator.Label = result.IsVisible
|
||||
? result.DisplayCount.ToString(System.Globalization.CultureInfo.InvariantCulture)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if <paramref name="guid"/> is one of the currently-active shortcut guids
|
||||
/// (i.e., present in the live <see cref="AcDream.Core.Items.ShortcutStore"/>).
|
||||
|
|
@ -264,12 +321,13 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
Action<uint>? selectItem = null,
|
||||
Func<uint>? selectedObjectId = null,
|
||||
Func<uint>? playerGuid = null,
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null)
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null,
|
||||
UiDatFont? ammoFont = null)
|
||||
{
|
||||
var c = new ToolbarController(layout, repo, shortcuts, iconIds, useItem, combatState,
|
||||
peaceDigits, warDigits, emptyDigits, itemInteraction,
|
||||
sendAddShortcut, sendRemoveShortcut, toggleCombat, selectItem,
|
||||
selectedObjectId, playerGuid, sendPutItemInContainer);
|
||||
selectedObjectId, playerGuid, sendPutItemInContainer, ammoFont);
|
||||
c.Populate();
|
||||
return c;
|
||||
}
|
||||
|
|
@ -638,5 +696,6 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
_repo.ObjectAdded -= OnRepositoryObjectChanged;
|
||||
_repo.ObjectUpdated -= OnRepositoryObjectChanged;
|
||||
_repo.ObjectRemoved -= OnRepositoryObjectChanged;
|
||||
_repo.ObjectMoved -= OnRepositoryObjectMoved;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,7 +390,8 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
selectItem: guid => b.Selection.Select(guid, SelectionChangeSource.Toolbar),
|
||||
selectedObjectId: () => b.Selection.SelectedObjectId ?? 0u,
|
||||
playerGuid: b.PlayerGuid,
|
||||
sendPutItemInContainer: b.SendPutItemInContainer);
|
||||
sendPutItemInContainer: b.SendPutItemInContainer,
|
||||
ammoFont: _bindings.Assets.DefaultFont);
|
||||
ToolbarInputController = new ToolbarInputController(ToolbarController, b.Selection);
|
||||
SelectedObjectController = Layout.SelectedObjectController.Bind(
|
||||
layout,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue