Demos/TarkovInventory/StashItem.cs
using System.Collections.Generic;
namespace Sandbox.TarkovInventory;
// Coarse item category. Drives the per-type tile tint (solid stand-in for per-type gradients; Goo has no typed gradient primitive yet) and, later, equip-slot validation.
public enum ItemKind { Gem, Helmet, Rifle, Magazine }
// An item with a footprint, keyed by Id. Icons reuse the existing demo SVGs. Count drives the
// bottom-middle stack label (shown only when > 1, per inventory convention). Short is the
// abbreviated name shown on 1-cell-wide tiles where the full name will not fit (e.g. "Mag").
public sealed record StashItem( string Id, string Name, string Short, ItemKind Kind, string Icon, int W, int H, int Count = 1, int MaxStack = 1 )
{
// Same kind and both stackable (MaxStack > 1) means a drop merges instead of moving.
public static bool CanStack( StashItem a, StashItem b ) => a.Kind == b.Kind && a.MaxStack > 1 && b.MaxStack > 1;
// Merge source into target up to target.MaxStack; returns the filled target and any leftover that did not fit.
public static (StashItem target, int leftover) Stack( StashItem source, StashItem target )
{
int total = source.Count + target.Count;
int newCount = total <= target.MaxStack ? total : target.MaxStack;
return (target with { Count = newCount }, total - newCount);
}
// Round-up half: the slider's default split-off amount (5 -> 3, 4 -> 2, 3 -> 2, 2 -> 1).
public static int DefaultSplit( int count ) => (count + 1) / 2;
// Peel n off source into a new stack with id newId. Precondition: 1 <= n < source.Count.
// Returns the reduced source and the new peeled stack; conserves the total count.
public static (StashItem reduced, StashItem peeled) Split( StashItem source, int n, string newId )
{
if ( n < 1 || n >= source.Count )
throw new System.ArgumentOutOfRangeException( nameof( n ), n, $"split amount must be in 1..{source.Count - 1}" );
return (source with { Count = source.Count - n }, source with { Id = newId, Count = n });
}
}
static class StashCatalog
{
// a dense synthetic mix (~48 of 90 cells) to exercise the grid near capacity.
public static IEnumerable<StashItem> Dense()
{
int[] gemCounts = { 1, 1, 2, 2, 3, 3, 4, 1 }; // spread so UAT reaches a full stack (cap 5) and an overflow fast
for ( int i = 0; i < 8; i++ ) yield return new StashItem( $"gem{i}", "Gem", "Gem", ItemKind.Gem, "SVGs/gem.svg", 1, 1, Count: gemCounts[i], MaxStack: 5 );
for ( int i = 0; i < 4; i++ ) yield return new StashItem( $"helm{i}", "Helmet", "Hel", ItemKind.Helmet, "SVGs/helmet.svg", 2, 2 );
for ( int i = 0; i < 2; i++ ) yield return new StashItem( $"rifle{i}", "Rifle", "Rif", ItemKind.Rifle, "SVGs/rifle.svg", 2, 4 );
for ( int i = 0; i < 4; i++ ) yield return new StashItem( $"mag{i}", "Magazine", "Mag", ItemKind.Magazine, "SVGs/magazine.svg", 1, 2, 30 );
}
}