DarkWeb.cs

UI/gameplay helper for a fictional "dark web" shop. Manages a multi-step checkout flow, fake vendor and network hop info, prices and labels, and delegates actual purchases to Shop/TrainingSystem/EndingSystem; exposes state and tick logic.

NetworkingEmbedded Secret
namespace NoChillquarium;

/// <summary>Shady marketplace listing the player is "browsing" on the dark web shop.</summary>
public enum DarkListing
{
	None,
	Meth,
	M80,
	Syringe,
	Wmd,
	Whale
}

/// <summary>
/// Multi-step buy confirm for Shady items (still just spends in-game Ð).
/// </summary>
public static class DarkWeb
{
	static readonly Random _rng = new();
	static int _version;
	static DarkListing _listing = DarkListing.None;
	static int _step; // 0 connect, 1 confirm, 2 pay
	static float _stepTimer;
	static string _status = "";
	static string _vendor = "";
	static int _hops = 7;
	static int _stars = 4;

	public static int Version => _version;
	public static bool CheckoutOpen => _listing != DarkListing.None;
	public static DarkListing Listing => _listing;
	public static int Step => _step;
	public static string Status => _status;
	public static string Vendor => _vendor;
	public static int Hops => _hops;
	public static int Stars => _stars;

	public static string SiteTitle => "Shop";
	public static string SiteOnion => "";

	public static string StepLabel => _step switch
	{
		0 => "LOADING",
		1 => "CONFIRM",
		2 => "PAY",
		_ => ""
	};

	public static string ItemName => _listing switch
	{
		DarkListing.Meth => "Meth bag",
		DarkListing.M80 => "M80 stick",
		DarkListing.Syringe => "Juice kit",
		DarkListing.Wmd => "Suspicious crate",
		DarkListing.Whale => "Blue whale",
		_ => ""
	};

	public static string ItemNote => _listing switch
	{
		DarkListing.Meth => "Zoomies",
		DarkListing.M80 => "Tape · boom",
		DarkListing.Syringe => "Inject from tools",
		DarkListing.Wmd => "No-chill key",
		DarkListing.Whale => "No-chill key",
		_ => ""
	};

	public static double ItemPrice => _listing switch
	{
		DarkListing.Meth => Shop.MethCost,
		DarkListing.M80 => Shop.M80Cost,
		DarkListing.Syringe => TrainingSystem.SyringeCost,
		DarkListing.Wmd => EndingSystem.WmdCost,
		DarkListing.Whale => EndingSystem.WhaleCost,
		_ => 0
	};

	public static string PriceLabel =>
		"Ð" + Economy.FormatDoge( ItemPrice );

	public static string PayButtonLabel =>
		"Pay " + PriceLabel;

	public static bool CanAfford =>
		Economy.Balance >= ItemPrice - 0.001;

	public static string StarsText => "";


	public static void Clear()
	{
		_listing = DarkListing.None;
		_step = 0;
		_stepTimer = 0f;
		_status = "";
		_vendor = "";
		_version++;
	}

	public static void Tick( float dt )
	{
		if ( _listing == DarkListing.None || dt <= 0f )
			return;

		if ( _step != 0 )
			return;

		_stepTimer -= dt;
		if ( _stepTimer > 0f )
		{
			_version++;
			return;
		}

		// Brief pause then confirm step
		if ( _hops > 3 )
		{
			_hops--;
			_status = "Loading…";
			_stepTimer = 0.2f;
			_version++;
			return;
		}

		_step = 1;
		_status = "Confirm purchase.";
		GameAudio.PlayUi( GameAudio.Notice );
		_version++;
	}

	public static bool TryBegin( DarkListing listing )
	{
		if ( listing == DarkListing.None || !TankSim.IsActive )
			return false;

		// Soft gates before opening the theater
		if ( listing == DarkListing.Syringe && !TrainingSystem.SteroidsUnlocked )
		{
			TankSim.ShowBanner( $"Juice {TrainingSystem.SteroidUnlockText.ToLower()}." );
			GameAudio.PlayUi( GameAudio.Error );
			return false;
		}
		if ( listing == DarkListing.Wmd && EndingSystem.HasWmd )
		{
			TankSim.ShowBanner( "You already bought the crate. Stop refreshing." );
			GameAudio.PlayUi( GameAudio.Error );
			return false;
		}
		if ( listing == DarkListing.Wmd && Economy.PlaytimeSeconds < EndingSystem.WmdUnlockPlaytime )
		{
			TankSim.ShowBanner( $"Not available yet. {EndingSystem.WmdUnlockText}." );
			GameAudio.PlayUi( GameAudio.Error );
			return false;
		}
		if ( listing == DarkListing.Whale && EndingSystem.HasWhale )
		{
			TankSim.ShowBanner( "Whale already on the books." );
			GameAudio.PlayUi( GameAudio.Error );
			return false;
		}
		if ( listing == DarkListing.Whale && Economy.PlaytimeSeconds < EndingSystem.WhaleUnlockPlaytime )
		{
			TankSim.ShowBanner( $"Whale listing sealed. {EndingSystem.WhaleUnlockText}." );
			GameAudio.PlayUi( GameAudio.Error );
			return false;
		}

		_listing = listing;
		_step = 0;
		_hops = 7;
		_stars = 3 + _rng.Next( 0, 3 );
		_vendor = PickVendor( listing );
		_status = "Getting ready…";
		_stepTimer = 0.35f;
		GameAudio.PlayUi( GameAudio.Tape );
		_version++;
		return true;
	}

	public static void ContinueFromVendor()
	{
		if ( _listing == DarkListing.None || _step != 1 )
			return;
		_step = 2;
		_status = "Ready to pay.";
		GameAudio.PlayUi( GameAudio.Pop );
		_version++;
	}

	public static void Cancel()
	{
		if ( _listing == DarkListing.None )
			return;
		var was = _listing;
		Clear();
		Shop.SetLastMessage( "Cancelled." );
		GameAudio.PlayUi( GameAudio.Close );
		_ = was;
		_version++;
	}

	/// <summary>Final pay step — spends Ð and grants the listing.</summary>
	public static bool ConfirmPay()
	{
		if ( _listing == DarkListing.None || _step != 2 )
			return false;

		var kind = _listing;
		bool ok;
		switch ( kind )
		{
			case DarkListing.Meth:
				ok = Shop.TryBuyMeth();
				break;
			case DarkListing.M80:
				ok = Shop.TryBuyM80();
				break;
			case DarkListing.Syringe:
				ok = TrainingSystem.TryBuySyringe();
				break;
			case DarkListing.Wmd:
				ok = EndingSystem.TryBuyWmd();
				break;
			case DarkListing.Whale:
				ok = EndingSystem.TryBuyWhale();
				break;
			default:
				ok = false;
				break;
		}

		if ( !ok )
		{
			_status = "Not enough Ð.";
			GameAudio.PlayUi( GameAudio.Error );
			_version++;
			return false;
		}

		var drop = kind switch
		{
			DarkListing.Meth => "Meth bag bought.",
			DarkListing.M80 => "M80 bought.",
			DarkListing.Syringe => "Juice kit bought.",
			DarkListing.Wmd => "Crate bought.",
			DarkListing.Whale => "Blue whale bought.",
			_ => "Bought."
		};
		Shop.SetLastMessage( drop );
		TankSim.ShowBanner( drop );
		Clear();
		_version++;
		return true;
	}

	static string PickVendor( DarkListing listing ) => listing switch
	{
		DarkListing.Meth => Pick( "FishyPharma", "BathSaltBob", "TankChemist", "rx_guppy" ),
		DarkListing.M80 => Pick( "BoomDrop", "TapeAndPray", "FirecrackerFin", "m80_anon" ),
		DarkListing.Syringe => Pick( "VetOnTheSide", "BulkAmp", "ScaleDoctor", "fin_juice_co" ),
		DarkListing.Wmd => Pick( "crate_anon", "NoQuestionsLtd", "RedactedVendor", "oops_military" ),
		DarkListing.Whale => Pick( "DeepListing", "MemeLogistics", "BlueEscrow", "ocean_jokes" ),
		_ => "anon"
	};

	static string Pick( params string[] names ) =>
		names[_rng.Next( names.Length )];

	static string FakeNode() => Pick(
		"relay-nl", "exit-is", "bridge-ca", "guard-de", "middle-se", "snowflake-??" );
}