DarkWeb.cs

UI/gameplay helper that models a fictional "dark web" shop for in-game purchases. It tracks the current listing, vendor, step/status, exposes read-only properties for UI, validates gating conditions, and handles purchase flow by calling Shop, TrainingSystem, EndingSystem, Economy and audio/UI helpers.

NetworkingFile Access
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>
/// Shady checkout — one-click buy for everyday items.
/// WMD / whale keep a single pay confirm (high stakes).
/// </summary>
public static class DarkWeb
{
	static readonly Random _rng = new();
	static int _version;
	static DarkListing _listing = DarkListing.None;
	static int _step; // 0 unused · 1 unused · 2 pay (danger items only)
	static string _status = "";
	static string _vendor = "";

	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 => 0;
	public static int Stars => 0;

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

	public static string StepLabel => _step switch
	{
		2 => "PAY",
		_ => "BUY"
	};

	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;
		_status = "";
		_vendor = "";
		_version++;
	}

	public static void Tick( float dt )
	{
		// No multi-hop theater — buys are instant or one pay click.
		_ = dt;
	}

	/// <summary>
	/// Everyday shady goods buy on the spot (one click from the shop row).
	/// WMD / whale open a single pay step.
	/// </summary>
	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." );
			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;
		}

		// Instant buy for routine shady stock.
		if ( listing is DarkListing.Meth or DarkListing.M80 or DarkListing.Syringe )
		{
			_listing = listing;
			_step = 2;
			_vendor = PickVendor( listing );
			var ok = ConfirmPay();
			return ok;
		}

		// Danger items: one pay click only.
		_listing = listing;
		_step = 2;
		_vendor = PickVendor( listing );
		_status = "Ready to pay.";
		GameAudio.PlayUi( GameAudio.Tape );
		_version++;
		return true;
	}

	public static void ContinueFromVendor()
	{
		// Legacy hook — jump to pay.
		if ( _listing == DarkListing.None )
			return;
		_step = 2;
		_status = "Ready to pay.";
		GameAudio.PlayUi( GameAudio.Pop );
		_version++;
	}

	public static void Cancel()
	{
		if ( _listing == DarkListing.None )
			return;
		Clear();
		Shop.SetLastMessage( "Cancelled." );
		GameAudio.PlayUi( GameAudio.Close );
		_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 );
			// Instant path already closed listing on success only — keep open for danger pay retry.
			if ( kind is DarkListing.Meth or DarkListing.M80 or DarkListing.Syringe )
				Clear();
			_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. Grandma: \"Fancy. Don't put it in the bath.\"",
			_ => "Bought."
		};
		Shop.SetLastMessage( drop );
		TankSim.ShowBanner( drop );
		GameAudio.PlayUi( GameAudio.Confirm );
		Clear();
		return true;
	}

	static string PickVendor( DarkListing listing ) => listing switch
	{
		DarkListing.Meth => "lot_chemist",
		DarkListing.M80 => "unit_4b_garage",
		DarkListing.Syringe => "bingo_nurse",
		DarkListing.Wmd => "no_reply",
		DarkListing.Whale => "aquarium_fence",
		_ => "unknown"
	};
}