using System;
using System.Globalization;
namespace AcDream.Core.Items;
///
/// Shared owner for retail GenItemHolder::splitSize and
/// GenItemHolder::maxSplitSize. The toolbar entry/slider edits this state and
/// item-holder operations consume the same value.
///
public sealed class StackSplitQuantityState
{
public uint Value { get; private set; } = 1u;
public uint Maximum { get; private set; } = 1u;
public float Ratio => Value / (float)Maximum;
public event Action? Changed;
public void Reset(uint stackSize, uint? initialValue = null)
{
uint maximum = Math.Max(stackSize, 1u);
Set(initialValue ?? maximum, maximum);
}
public void SetFromText(string? text)
{
// Retail uses wcstoul, whose invalid/empty result is zero, then clamps to one.
uint parsed = uint.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out uint value)
? value
: 0u;
SetValue(parsed);
}
///
/// Ports gmToolbarUI::ListenToElementMessage @ 0x004BEFE0 and
/// UIElement_Scrollbar::SetScrollbarPosition @ 0x00470EC0. The scrollbar
/// first truncates its normalized position to an integer in [0,1000], then the
/// toolbar converts it to 1 + floor(position * max / 1000) and clamps.
///
public void SetFromSliderRatio(float ratio)
{
float clamped = Math.Clamp(ratio, 0f, 1f);
uint positionMillis = (uint)MathF.Truncate(clamped * 1000f);
ulong scaled = (ulong)positionMillis * Maximum;
uint value = 1u + (uint)(scaled / 1000u);
SetValue(value);
}
public void SetValue(uint value) => Set(value, Maximum);
///
/// Ports ItemHolder::GetObjectSplitSize @ 0x00586F00: only the
/// currently selected object consumes GenItemHolder::splitSize.
/// Every other object operation uses that object's full stack size.
///
public uint GetObjectSplitSize(uint objectId, uint selectedObjectId, uint objectStackSize)
{
if (objectId == selectedObjectId)
return Value;
return Math.Max(objectStackSize, 1u);
}
private void Set(uint value, uint maximum)
{
maximum = Math.Max(maximum, 1u);
value = Math.Clamp(value, 1u, maximum);
if (Value == value && Maximum == maximum)
return;
Value = value;
Maximum = maximum;
Changed?.Invoke();
}
}