Console command helpers for managing in-game trade tables. Provides commands to place, list, clear, empty, and use trade tables tied to the active config and runtime TradeTable instances.
using System.Linq;
using Sandbox;
namespace NZombies;
/// <summary>
/// Console access to the trading table.
///
/// ⚠️ THE ONLY WAY TO PLACE ONE TODAY, like the ammo box — the map-editor tool waits on the real
/// model (upstream's is `models/zmb/bo2/tranzit/zm_work_bench.mdl`). Tables placed with `nz_trade`
/// save into the config identically, so they survive into whatever the tool becomes.
/// </summary>
public static class TradeTableCommands
{
static NZPlayer Player
=> PlayerCharacters.Local()
?? NZPlayer.Local;
/// <summary>Drop one at your feet: `nz_trade`.</summary>
[ConCmd( "nz_trade" )]
public static void Place()
{
var p = Player;
if ( !p.IsValid() ) { Log.Warning( "[nz-trade] no player" ); return; }
var cfg = ActiveConfig.Current;
if ( cfg is null ) { Log.Warning( "[nz-trade] no config" ); return; }
cfg.TradeTables.Add( new TradeTableSpot
{
Position = p.WorldPosition,
Yaw = p.EyeAngles.yaw + 180f,
Normal = Vector3.Up,
} );
TradeTableManager.Ensure()?.Rebuild();
Log.Info( $"[nz-trade] placed — {cfg.TradeTables.Count} total" );
}
/// <summary>What is placed, and what is on each: `nz_trade_list`.</summary>
[ConCmd( "nz_trade_list" )]
public static void List()
{
var list = ActiveConfig.Current?.TradeTables;
if ( list is null || list.Count == 0 )
{
Log.Info( "[nz-trade] none placed — nz_trade to drop one" );
return;
}
for ( int i = 0; i < list.Count; i++ )
{
var s = list[i];
Log.Info( $"[nz-trade] [{i}] {s.Position}"
+ (s.RequiresPower ? " ⚡power" : "")
+ $" flag {DoorLinks.Display( s.Link )}" );
}
// ⚠️ THE CONTENTS ARE READ OFF THE LIVE TABLES, not the config — what a table is holding is
// runtime state and deliberately not saved with the map.
foreach ( var t in TradeTable.All.Where( t => t.IsValid() ) )
{
Log.Info( $"[nz-trade] {t.WorldPosition} holding "
+ (t.HasWeapon
? $"{t.StoredName} (MK{t.StoredPap}, {Rarity.NameFor( t.StoredRarity )}, "
+ $"{t.StoredReserve} spare)"
: "nothing") );
}
var mgr = TradeTableManager.Instance;
Log.Info( $"[nz-trade] {list.Count} configured, "
+ (mgr.IsValid() ? $"{mgr.Built} standing" : "no manager — none standing") );
}
/// <summary>Remove them all: `nz_trade_clear`.</summary>
[ConCmd( "nz_trade_clear" )]
public static void Clear()
{
var cfg = ActiveConfig.Current;
if ( cfg is null ) return;
int n = cfg.TradeTables.Count;
cfg.TradeTables.Clear();
TradeTableManager.Ensure()?.Rebuild();
Log.Info( $"[nz-trade] cleared {n}" );
}
/// <summary>
/// Empty every table without removing them: `nz_trade_empty`.
///
/// ⚠️ SEPARATE FROM `nz_trade_clear`, which removes the tables themselves. Getting a stuck
/// weapon back out is a different job from un-placing the furniture.
/// </summary>
[ConCmd( "nz_trade_empty" )]
public static void Empty()
{
int n = 0;
foreach ( var t in TradeTable.All.Where( t => t.IsValid() && t.HasWeapon ) )
{
t.Empty();
n++;
}
Log.Info( $"[nz-trade] emptied {n} table(s)" );
}
/// <summary>
/// Use the nearest table without walking to it: `nz_trade_use`.
///
/// ⚠️ FALLS BACK TO ANY PLACED TABLE, because a feature reachable only by standing in the right
/// spot cannot be tested remotely — the same rule `nz_ammobox_buy` follows.
/// </summary>
[ConCmd( "nz_trade_use" )]
public static void Use()
{
var p = Player;
if ( !p.IsValid() ) { Log.Warning( "[nz-trade] no player" ); return; }
var table = TradeTable.Near( p.WorldPosition )
?? TradeTable.All.FirstOrDefault( t => t.IsValid() );
if ( !table.IsValid() ) { Log.Warning( "[nz-trade] no table placed — nz_trade" ); return; }
var msg = table.Use( p );
Log.Info( $"[nz-trade] {(string.IsNullOrWhiteSpace( msg ) ? "(nothing happened)" : msg)}" );
}
}