A static manager that runs a simple Blackjack mini-game between two Player objects. It deals random cards, presents a choice popup for Hit or Stand, resolves AI drawing rules, and applies scaled HP damage via CombatManager based on prestige from GameManager.
using Keyboard_Warriors_.Models;
using Keyboard_Warriors_.Systems;
using Sandbox;
using System;
namespace Keyboard_Warriors_.Managers;
public static class BlackjackEventRunner
{
private static Player cachedPlayer;
private static Player cachedAI;
private static int secretAITotal;
// In Blackjack, 11 represents an Ace.
// Random.Shared.Next(1, 12) generates numbers 1 through 11 inclusive.
private static int DrawCard() => Random.Shared.Next( 1, 12 );
public static void StartEvent( Player player, Player ai )
{
GameManager.AddLog( "** A game of BLACKJACK begins! **" );
cachedPlayer = player;
cachedAI = ai;
// Deal starting hands securely
int currentScalePlayerTotal = DrawCard() + DrawCard();
secretAITotal = DrawCard() + DrawCard();
GameManager.AddLog( $"You are dealt cards totaling: {currentScalePlayerTotal}" );
GameManager.AddLog( $"AI is showing: {secretAITotal / 2} (one card hidden)" );
GameManager.AddLog( "⚠️ AWAITING HIT/STAND PROTOCOL CHOICE..." );
// Kick off the interactive turn loop
RunBlackjackTurnLoop( currentScalePlayerTotal );
}
private static void RunBlackjackTurnLoop( int runningPlayerTotal )
{
// 1. Safely resolve your scene instance to read current progression statistics for the bust check
var manager = Sandbox.Game.ActiveScene?.Get<GameManager>();
int prestige = manager != null ? manager.CurrentPrestige : 0;
int scaledWinDamage = 25 + (prestige * 3);
// Immediate containment check if a fresh Hit pushes them over the limit
if ( runningPlayerTotal > 21 )
{
GameManager.AddLog( $"** Total: {runningPlayerTotal} - You BUST! AI wins automatically. -{scaledWinDamage} HP. **" );
CombatManager.applyDamage( ref cachedPlayer, scaledWinDamage );
GameManager.AddLog( $"{cachedPlayer.name} | HP: {cachedPlayer.hp} | Armor: {cachedPlayer.defense}" );
return;
}
var blackjackEvent = new ChoiceEvent
{
Title = "🃏 CYBER BLACKJACK EMULATION",
PromptText = $"Your current hand value sits at: {runningPlayerTotal}. The AI is presenting a split risk window. Will you request an additional card packet or lock this calculation down?",
};
// --- OPTION 1: HIT ---
blackjackEvent.Options.Add( new EventOption
{
ButtonText = "➕ REQUEST CARD (HIT)",
ActionToExecute = async () =>
{
int freshCard = DrawCard();
int updatedTotal = runningPlayerTotal + freshCard;
GameManager.AddLog( $"You draw a {freshCard}. Total: {updatedTotal}" );
// Force a tiny frame delay so s&box can safely process the UI transition
await GameTask.Delay( 50 );
// Clean state-safe recursion
RunBlackjackTurnLoop( updatedTotal );
}
} );
// --- OPTION 2: STAND ---
blackjackEvent.Options.Add( new EventOption
{
ButtonText = "🔒 STAND WITH TOTAL",
ActionToExecute = () =>
{
ResolveDealerAndMatch( runningPlayerTotal );
}
} );
GameManager.Instance.TriggerChoicePopup( blackjackEvent );
}
private static void ResolveDealerAndMatch( int finalPlayerTotal )
{
// 2. Safely resolve your scene instance to read current progression statistics for match resolution
var manager = Sandbox.Game.ActiveScene?.Get<GameManager>();
int prestige = manager != null ? manager.CurrentPrestige : 0;
// 3. Lineally scale your payout variables (+5 for natural Blackjack, +3 for standard win, +2 for ties per level)
int scaledBlackjackDamage = 40 + (prestige * 5);
int scaledWinDamage = 25 + (prestige * 3);
int scaledTieDamage = 10 + (prestige * 2);
// Direct immediate check for natural Blackjacks
if ( finalPlayerTotal == 21 )
{
GameManager.AddLog( $"** BLACKJACK!! AI loses -{scaledBlackjackDamage} HP! **" );
CombatManager.applyDamage( ref cachedAI, scaledBlackjackDamage );
return;
}
GameManager.AddLog( $"You stand with {finalPlayerTotal}." );
GameManager.AddLog( $"AI reveals hidden total: {secretAITotal}" );
int aiRunningTotal = secretAITotal;
while ( aiRunningTotal < 17 )
{
int card = DrawCard();
aiRunningTotal += card;
GameManager.AddLog( $"AI draws a {card}. Total: {aiRunningTotal}" );
}
// Core win/loss evaluation conditions using scaled values
if ( aiRunningTotal == 21 )
{
GameManager.AddLog( $"** AI hits 21! You lose {scaledBlackjackDamage} HP! **" );
CombatManager.applyDamage( ref cachedPlayer, scaledBlackjackDamage );
}
else if ( aiRunningTotal > 21 || finalPlayerTotal > aiRunningTotal )
{
GameManager.AddLog( $"** You win with {finalPlayerTotal} vs {aiRunningTotal}! AI loses {scaledWinDamage} HP! **" );
CombatManager.applyDamage( ref cachedAI, scaledWinDamage );
}
else if ( aiRunningTotal > finalPlayerTotal )
{
GameManager.AddLog( $"** AI wins with {aiRunningTotal} vs {finalPlayerTotal}! You lose {scaledWinDamage} HP! **" );
CombatManager.applyDamage( ref cachedPlayer, scaledWinDamage );
}
else
{
GameManager.AddLog( $"** Tie! Both lose {scaledTieDamage} HP. **" );
CombatManager.applyDamage( ref cachedPlayer, scaledTieDamage );
CombatManager.applyDamage( ref cachedAI, scaledTieDamage );
}
GameManager.AddLog( $"{cachedPlayer.name} | HP: {cachedPlayer.hp} | Armor: {cachedPlayer.defense}" );
GameManager.AddLog( $"{cachedAI.name} | HP: {cachedAI.hp} | Armor: {cachedAI.defense}" );
}
}