AmmoModel represents a weapon ammo system with a magazine and reserve. It tracks mag size, reserve, reload timing and progress, supports firing, starting reloads, auto-reload, resetting and ticking reload progress.
using System;
namespace Goo.FpsUI;
// Ammo logic: a magazine + reserve, a timed reload that pulls rounds from reserve. Engine-free.
public sealed class AmmoModel
{
public int MagSize = 30; // rounds per full magazine
public float ReloadDuration = 1.6f; // seconds a reload takes
public bool AutoReload = true; // start a reload automatically once the magazine empties
public int Mag { get; private set; } = 30; // rounds in the magazine
public int Reserve { get; private set; } = 120; // rounds in reserve
public bool Reloading { get; private set; } // true mid-reload
float _reloadTime; // seconds remaining on the current reload
// 0 at reload start, ramps to 1 as it completes, 0 when not reloading.
public float ReloadProgress => Reloading && ReloadDuration > 0f
? 1f - Math.Clamp( _reloadTime / ReloadDuration, 0f, 1f )
: 0f;
public bool LowOnAmmo => MagSize > 0 && Mag <= MagSize * 0.2f; // at or below 20% of a magazine
public bool NeedsReloadHint => LowOnAmmo && !Reloading && Reserve > 0; // show the reload cue (low, idle, has reserve)
public void Reset() => Mag = MagSize; // call after setting MagSize
public void SetReserve( int rounds ) => Reserve = Math.Max( 0, rounds ); // set total reserve
public bool Fire() // consume one round, returns true only if a round was actually spent
{
if ( Reloading || Mag <= 0 ) return false;
Mag--;
return true;
}
public void Reload() // begin a reload, no-op if full, empty reserve, or already reloading
{
if ( Reloading || Reserve <= 0 || Mag >= MagSize ) return;
Reloading = true;
_reloadTime = ReloadDuration;
}
public bool Tick( float dt ) // advance an in-progress reload, true while reloading
{
if ( AutoReload && Mag == 0 && !Reloading && Reserve > 0 ) Reload(); // empty mag -> auto-reload
if ( !Reloading ) return false;
_reloadTime -= dt;
if ( _reloadTime > 0f ) return true;
int take = Math.Min( MagSize - Mag, Reserve );
Mag += take;
Reserve -= take;
Reloading = false;
return true;
}
}