using System.Collections.Generic; using System.Diagnostics; using System.Linq; using DonkeysAndDroids; using Godot; using RobotAndDonkey.Game; using RobotAndDonkey.Game.Execution; using RobotAndDonkey.Game.Execution.Commands; using RobotAndDonkey.Game.Execution.Requests; using RobotAndDonkey.Game.Execution.Results; using RobotAndDonkey.Game.GameState; using RobotAndDonkey.Game.Utils; public partial class Main : CanvasLayer { public enum EScreenId { Logo, MetaGame, CoreLoop, Victory } public override void _Ready() { #if DEBUG if (!Trace.Listeners.OfType().Any()) Trace.Listeners.Add(new DefaultTraceListener()); #endif Instance = this; m_Runtime = new(); m_Runtime.Published += (_, e) => OnGameEvent(e); m_Background = GetNode("Background"); m_LogoScreen = GetNode("LogoScreen"); m_MetaGameScreen = GetNode("MetaGameScreen"); m_CoreLoopScreen = GetNode("CoreLoopScreen"); m_VictoryScreen = GetNode("VictoryScreen"); OptionsMenu = GetNode("OptionsMenu"); m_CurrentScreen = m_LogoScreen; Music.Init(this); Music.PlaySong(MusicManager.ESong.MetaGame); } public void StartMetaGame() { Music.PlaySong(MusicManager.ESong.MetaGame); var tween = GetTree().CreateTween(); TransitionScreen(m_MetaGameScreen, tween); } public void TransitionScreen(T newScreen, Tween tween) where T : Control, IScreen { newScreen.EnableInputs(); if (m_CurrentScreen == newScreen) return; MoveChild(newScreen, 1); var oldControl = (Control)m_CurrentScreen; var oldScreen = m_CurrentScreen; m_CurrentScreen = newScreen; newScreen.Modulate = new(1, 1, 1); newScreen.Visible = true; newScreen.Activate(); tween.TweenProperty(oldControl, "modulate", new Color(0, 0, 0, 0), 0.25); tween.TweenCallback(Callable.From(() => { oldScreen.Deactivate(); oldControl.Visible = false; oldControl.Modulate = new(1, 1, 1); })); } public void StartCoreLoop(int seed, EDifficulty difficulty, ERobotType selectedRobot) { Seed = seed; CoreLoop = new(new((ulong)seed), new(selectedRobot, difficulty, seed)); m_Runtime.Start(CoreLoop); } private void OnGameEvent(GameEvent gameEvent) { switch (gameEvent.Payload) { case NextStepIssued { Step: { } request }: { m_NextRequest = request; if (m_Tween != null) break; ProcessNextRequest(); break; } case StepApplied { Results: var results }: { GD.Print("Results available"); foreach (var result in results) { Results.Enqueue(result); } break; } case StateChanged: { GD.Print("State changed"); m_Tween = GetTree().CreateTween(); while (Results.TryDequeue(out var result)) { GD.Print(result.ToString()); if (m_CurrentScreen.HandleResult(result, m_Tween)) m_Tween.SetParallel(false); else GD.Print("> Unhandled result!"); } m_Tween.TweenCallback(Callable.From(() => { m_Tween = null; ProcessNextRequest(); })); break; } case StepRejected r: { GD.Print($"Invalid action: {r.Reason}"); break; } case GameOver: { GD.Print("Game over"); break; } } } private void ProcessNextRequest() { m_CurrentScreen.DisableInputs(); CurrentRequest = m_NextRequest; m_NextRequest = null; GD.Print($"Next step: {CurrentRequest}"); m_Tween = GetTree().CreateTween(); var tween = m_Tween; switch (CurrentRequest) { case DrawGlitchRequest drawCardRequest: { Music.PlaySong(MusicManager.ESong.Shop); TransitionScreen(m_CoreLoopScreen, tween); m_CoreLoopScreen.DrawGlitch(drawCardRequest.Card, tween); break; } case ImproveRequest: { TransitionScreen(m_CoreLoopScreen, tween); m_CoreLoopScreen.Improve(tween); break; } case GambleRequest: { TransitionScreen(m_CoreLoopScreen, tween); m_CoreLoopScreen.CosmicRays(CoreLoop.BoosterPack, tween); break; } case BufferOverflowRequest: { TransitionScreen(m_CoreLoopScreen, tween); m_CoreLoopScreen.BufferOverflow(tween); break; } case ExecuteProgramRequest: { Music.PlaySong(MusicManager.ESong.CoreLoop); TransitionScreen(m_CoreLoopScreen, tween); m_CoreLoopScreen.ExecuteProgram(tween); break; } case ScoringRequest: { Music.PlaySong(MusicManager.ESong.Scoring); TransitionScreen(m_VictoryScreen, tween); m_VictoryScreen.Configure(CoreLoop, tween); break; } } } public void Execute(Command command) { if (command == null) return; GD.Print($"Execute {command}"); m_Runtime.Submit(command); } public static Main Instance { get; set; } public Request CurrentRequest { get; private set; } = Request.s_Empty; public Queue Results { get; } = []; public CoreLoop CoreLoop { get; private set; } public int Seed { get; private set; } public string StringSeed => SeedString.ToString(Seed); public MusicManager Music { get; } = new(); public OptionsMenu OptionsMenu { get; private set; } private Background m_Background; private CoreLoopScreen m_CoreLoopScreen; private IScreen m_CurrentScreen; private LogoScreen m_LogoScreen; private MetaGameScreen m_MetaGameScreen; private Request m_NextRequest; private GameRuntime m_Runtime; private Tween m_Tween; private VictoryScreen m_VictoryScreen; }