namespace AcDream.Core.Items;
///
/// Pure retail toolbar ammunition selection.
/// Retail references: gmToolbarUI::UpdateAmmoID @ 0x004BF210 and
/// gmToolbarUI::UpdateAmmoNumber @ 0x004BE9E0.
///
public static class ToolbarAmmoPolicy
{
public readonly record struct Result(uint ObjectId, int DisplayCount)
{
public bool IsVisible => ObjectId != 0;
}
///
/// Resolve the first equipped missile weapon. If it is stackable, retail
/// treats that stack as its own ammunition (thrown weapons). Otherwise it
/// resolves the first separately equipped missile-ammo object.
///
public static Result Resolve(IReadOnlyList inventoryPlacements)
{
ArgumentNullException.ThrowIfNull(inventoryPlacements);
ClientObject? missileWeapon = FindAtLocation(
inventoryPlacements,
EquipMask.MissileWeapon);
ClientObject? ammo = missileWeapon is { StackSizeMax: > 1 }
? missileWeapon
: FindAtLocation(inventoryPlacements, EquipMask.MissileAmmo);
return ammo is null
? default
: new Result(ammo.ObjectId, ammo.StackSize == 0 ? 1 : ammo.StackSize);
}
private static ClientObject? FindAtLocation(
IReadOnlyList inventoryPlacements,
EquipMask location)
{
// ACCWeenieObject::GetObjectAtLocation @ 0x0058CE00 returns the first
// inventory placement whose location mask intersects the requested mask.
foreach (ClientObject item in inventoryPlacements)
if ((item.CurrentlyEquippedLocation & location) != 0)
return item;
return null;
}
}