(Feat) Add Build
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ashwild.Inventory
|
||||
{
|
||||
/// <summary>
|
||||
/// The single source of truth for what happens when a stack meets another stack. Both rules below
|
||||
/// are pure — they know nothing about containers, networking or authority — so the exact same
|
||||
/// decision runs for an inventory-to-inventory drag (client-side), a chest-to-chest drag
|
||||
/// (server-side) and an inventory-to-chest drag (server-side, against the payload in flight).
|
||||
/// That is why a chest transfer behaves identically to moving an item inside the inventory.
|
||||
///
|
||||
/// There are exactly two operations, because the player expresses exactly two intents:
|
||||
/// <see cref="Move"/> when they aim at a precise destination, and <see cref="TryStack"/> when they
|
||||
/// let the game find a free spot (quick transfer, deposit-all, pickups).
|
||||
/// </summary>
|
||||
public static class SlotTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// Moves a stack onto a destination the player explicitly aimed at. Empty destination = the whole
|
||||
/// stack moves; same mergeable item = merge and leave the remainder in the source; anything else
|
||||
/// (different item, non-stackable, uses-tracked, or a full stack) = swap the two slots. Uses ride
|
||||
/// along with the content in every branch, so a worn item stays worn.
|
||||
/// Returns whether anything actually changed.
|
||||
/// </summary>
|
||||
public static bool Move(ref SlotContent source, ref SlotContent target)
|
||||
{
|
||||
if (source.IsEmpty) return false;
|
||||
|
||||
if (target.IsEmpty)
|
||||
{
|
||||
target = source;
|
||||
source = SlotContent.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CanMerge(source, target))
|
||||
{
|
||||
int space = target.Item.MaxStackSize - target.Quantity;
|
||||
int moved = Mathf.Min(source.Quantity, space);
|
||||
|
||||
target.Quantity += moved;
|
||||
source.Quantity -= moved;
|
||||
if (source.Quantity <= 0) source = SlotContent.Empty;
|
||||
|
||||
return moved > 0;
|
||||
}
|
||||
|
||||
SlotContent temp = source;
|
||||
source = target;
|
||||
target = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto-placement: pushes as much of <paramref name="incoming"/> into the target as it can accept,
|
||||
/// and never swaps — the player did not pick this slot, so displacing what is already there would
|
||||
/// be wrong. An empty target takes one instance of a uses-tracked item (each keeps its own uses
|
||||
/// bar) or up to a full stack otherwise. Returns whether the target changed, leaving the leftover
|
||||
/// in <paramref name="incoming"/> for the caller to keep placing.
|
||||
/// </summary>
|
||||
public static bool TryStack(ref SlotContent incoming, ref SlotContent target)
|
||||
{
|
||||
if (incoming.IsEmpty) return false;
|
||||
|
||||
ItemData item = incoming.Item;
|
||||
|
||||
if (target.IsEmpty)
|
||||
{
|
||||
int toPlace = item.HasUses || !item.IsStackable
|
||||
? 1
|
||||
: Mathf.Min(incoming.Quantity, item.MaxStackSize);
|
||||
|
||||
target = SlotContent.Of(item, toPlace, incoming.Uses);
|
||||
incoming.Quantity -= toPlace;
|
||||
if (incoming.Quantity <= 0) incoming = SlotContent.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CanMerge(incoming, target)) return false;
|
||||
|
||||
int space = target.Item.MaxStackSize - target.Quantity;
|
||||
int moved = Mathf.Min(incoming.Quantity, space);
|
||||
if (moved <= 0) return false;
|
||||
|
||||
target.Quantity += moved;
|
||||
incoming.Quantity -= moved;
|
||||
if (incoming.Quantity <= 0) incoming = SlotContent.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two stacks merge only when they are the same stackable item that does not track uses and the
|
||||
/// target still has room. Uses-tracked items never merge: each instance owns its uses bar, so
|
||||
/// merging them would silently destroy one item's wear.
|
||||
/// </summary>
|
||||
private static bool CanMerge(SlotContent source, SlotContent target)
|
||||
{
|
||||
ItemData item = source.Item;
|
||||
return target.Item == item
|
||||
&& item.IsStackable
|
||||
&& !item.HasUses
|
||||
&& target.Quantity < item.MaxStackSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user