MainHud/MontyHallEventRunner.cs

A static manager that runs a Monty Hall style minigame between a player and an AI. It creates choice popups via GameManager, logs progress, randomly assigns prize and choices, and applies damage via CombatManager based on outcomes.

NetworkingFile Access
using Keyboard_Warriors_.Models;
using Keyboard_Warriors_.Systems;
using Sandbox;
using System;

namespace Keyboard_Warriors_.Managers;

public static class MontyHallEventRunner
{
	private static Player cachedPlayer;
	private static Player cachedAI;
	private static int prizeDoor;
	private static int aiChoice;

	private static int DrawCard() => Random.Shared.Next( 1, 12 );

	// FIX: Safe helper method to fetch the GameManager directly from the active engine layout
	private static GameManager GetManager()
	{
		return Sandbox.Game.ActiveScene?.Get<GameManager>();
	}

	public static void StartEvent( Player player, Player ai )
	{
		// FIX: Defensive guard assertion prevents UI initialization crashes
		var manager = GetManager();
		if ( manager == null )
		{
			Log.Error( "[MONTY HALL CRITICAL] Failed to resolve GameManager instance from active scene loop parameters!" );
			return;
		}

		GameManager.AddLog( "** Welcome to the Monty Hall Challenge! **" );
		GameManager.AddLog( "Three doors stand before you. Behind one is VICTORY, behind the other is FAILURE." );
		GameManager.AddLog( "⚠️ AWAITING INITIAL SELECTION PATHWAY..." );

		cachedPlayer = player;
		cachedAI = ai;

		prizeDoor = Random.Shared.Next( 1, 4 );
		aiChoice = Random.Shared.Next( 1, 4 );

		var initialDoorEvent = new ChoiceEvent
		{
			Title = "🚪 THE SYSTEM ENTRY PATHWAY",
			PromptText = "Three closed mainframe firewall doors stand before your terminal cursor. Select your starting gateway entry:",
		};

		initialDoorEvent.Options.Add( new EventOption
		{
			ButtonText = "🚪 PICK DOOR #1",
			ActionToExecute = () => { GameManager.AddLog( "Player picks Door #1." ); PromptSwitchOrStay( 1 ); }
		} );

		initialDoorEvent.Options.Add( new EventOption
		{
			ButtonText = "🚪 PICK DOOR #2",
			ActionToExecute = () => { GameManager.AddLog( "Player picks Door #2." ); PromptSwitchOrStay( 2 ); }
		} );

		initialDoorEvent.Options.Add( new EventOption
		{
			ButtonText = "🚪 PICK DOOR #3",
			ActionToExecute = () => { GameManager.AddLog( "Player picks Door #3." ); PromptSwitchOrStay( 3 ); }
		} );

		// FIX: Execute popup utilizing the secure local manager link profile
		manager.TriggerChoicePopup( initialDoorEvent );
	}

	private static void PromptSwitchOrStay( int initialPlayerChoice )
	{
		var manager = GetManager();
		if ( manager == null ) return;

		int revealDoorPlayer;
		do
		{
			revealDoorPlayer = Random.Shared.Next( 1, 4 );
		}
		while ( revealDoorPlayer == prizeDoor || revealDoorPlayer == initialPlayerChoice );

		GameManager.AddLog( $"Host reveals Door #{revealDoorPlayer} for you... it's FAILURE!" );
		GameManager.AddLog( "⚠️ AWAITING STRATEGIC RE-ROUTE SYSTEM CONFIRMATION..." );

		var switchOrStayEvent = new ChoiceEvent
		{
			Title = "🔀 THE MONTY HALL PARADOX",
			PromptText = $"You initially selected Door #{initialPlayerChoice}. Host has revealed Door #{revealDoorPlayer} is a dead sector. Will you switch or stay?",
		};

		switchOrStayEvent.Options.Add( new EventOption
		{
			ButtonText = "🔄 SWITCH TO OTHER OPEN DOOR",
			ActionToExecute = () =>
			{
				int finalChoicePlayer = initialPlayerChoice;
				for ( int i = 1; i <= 3; i++ )
				{
					if ( i != initialPlayerChoice && i != revealDoorPlayer )
					{
						finalChoicePlayer = i;
						break;
					}
				}
				GameManager.AddLog( $"You decide to SWITCH to Door #{finalChoicePlayer}!" );
				ResolveFinalMontyHallMatch( finalChoicePlayer );
			}
		} );

		switchOrStayEvent.Options.Add( new EventOption
		{
			ButtonText = "🔒 STAY WITH ORIGINAL SELECTION",
			ActionToExecute = () =>
			{
				GameManager.AddLog( $"You decide to STAY with Door #{initialPlayerChoice}." );
				ResolveFinalMontyHallMatch( initialPlayerChoice );
			}
		} );

		// FIX: Execute popup utilizing the secure local manager link profile
		manager.TriggerChoicePopup( switchOrStayEvent );
	}

	private static void ResolveFinalMontyHallMatch( int finalChoicePlayer )
	{
		var manager = GetManager();
		int prestige = manager != null ? manager.CurrentPrestige : 0;

		// Lineally scale your outcome damage vector (+4 per prestige level)
		int scaledMatchDamage = 35 + (prestige * 4);

		GameManager.AddLog( $"AI picks Door #{aiChoice}." );

		int revealDoorAI;
		do
		{
			revealDoorAI = Random.Shared.Next( 1, 4 );
		}
		while ( revealDoorAI == prizeDoor || revealDoorAI == aiChoice );

		GameManager.AddLog( $"Host reveals Door #{revealDoorAI} for AI... it's FAILURE!" );

		bool aiSwitch = Random.Shared.Next( 0, 2 ) == 1;
		int finalChoiceAI = aiChoice;

		if ( aiSwitch )
		{
			for ( int i = 1; i <= 3; i++ )
			{
				if ( i != aiChoice && i != revealDoorAI )
				{
					finalChoiceAI = i;
					break;
				}
			}
			GameManager.AddLog( $"AI decides to SWITCH to Door #{finalChoiceAI}!" );
		}
		else
		{
			GameManager.AddLog( $"AI decides to STAY with Door #{finalChoiceAI}." );
		}

		if ( finalChoicePlayer == prizeDoor )
		{
			GameManager.AddLog( $"** YOU WIN! The prize was behind Door #{prizeDoor}! AI loses {scaledMatchDamage} HP! **" );
			CombatManager.applyDamage( ref cachedAI, scaledMatchDamage );
		}
		else
		{
			GameManager.AddLog( $"** YOU LOSE! The prize was behind Door #{prizeDoor}! You lose {scaledMatchDamage} HP! **" );
			CombatManager.applyDamage( ref cachedPlayer, scaledMatchDamage );
		}

		if ( finalChoiceAI == prizeDoor )
		{
			GameManager.AddLog( $"** AI WINS! The prize was behind Door #{prizeDoor}! You take {scaledMatchDamage} HP damage! **" );
			CombatManager.applyDamage( ref cachedPlayer, scaledMatchDamage );
		}
		else
		{
			GameManager.AddLog( $"** AI LOSES! The prize was behind Door #{prizeDoor}! AI takes {scaledMatchDamage} HP damage! **" );
			CombatManager.applyDamage( ref cachedAI, scaledMatchDamage );
		}

		GameManager.AddLog( $"{cachedPlayer.name} | HP: {cachedPlayer.hp} | Armor: {cachedPlayer.defense}" );
		GameManager.AddLog( $"{cachedAI.name} | HP: {cachedAI.hp} | Armor: {cachedAI.defense}" );
	}
}