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.
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-??" );
}