Overhaul game state logic to support gameplay loop

This commit is contained in:
2025-04-30 00:43:55 -07:00
parent 78cdda97b9
commit 68c91d8f13
60 changed files with 2503 additions and 1116 deletions

View File

@@ -1,36 +0,0 @@
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public static class Input
{
public readonly record struct StartGame;
public readonly record struct Initialize;
public readonly record struct GoToOverworld;
public readonly record struct SaveGame;
public readonly record struct OpenInventory;
public readonly record struct CloseInventory;
public readonly record struct FloorExitReached;
public readonly record struct HideFloorClearMenu;
public readonly record struct GameOver;
public readonly record struct GoToNextFloor;
public readonly record struct PauseGame;
public readonly record struct UnpauseGame;
public readonly record struct PauseMenuTransitioned;
public readonly record struct AskForTeleport;
public readonly record struct HideAskForTeleport;
}
}

View File

@@ -1,39 +0,0 @@
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public static class Output
{
public readonly record struct StartGame;
public readonly record struct ShowPauseMenu;
public readonly record struct HidePauseMenu;
public readonly record struct ExitPauseMenu;
public readonly record struct SetPauseMode(bool IsPaused);
public readonly record struct ShowLostScreen;
public readonly record struct ExitLostScreen;
public readonly record struct LoadNextFloor;
public readonly record struct LoadMap;
public readonly record struct ShowFloorClearMenu;
public readonly record struct ExitFloorClearMenu;
public readonly record struct ShowAskForTeleport;
public readonly record struct HideAskForTeleport;
public readonly record struct GoToOverworld;
public readonly record struct SaveGame;
public readonly record struct DoubleExpTimeStart(int lengthOfTimeInSeconds);
}
}

View File

@@ -1,35 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
[Meta]
public abstract partial record State : StateLogic<State>
{
protected State()
{
OnAttach(() =>
{
var gameRepo = Get<IGameRepo>();
gameRepo.IsPaused.Sync += OnIsPaused;
gameRepo.DoubleExpTimeStart += OnDoubleExpTimeStart;
gameRepo.Ended += OnGameEnded;
});
OnDetach(() =>
{
var gameRepo = Get<IGameRepo>();
gameRepo.IsPaused.Sync -= OnIsPaused;
gameRepo.DoubleExpTimeStart -= OnDoubleExpTimeStart;
gameRepo.Ended -= OnGameEnded;
});
}
private void OnDoubleExpTimeStart(int lengthOfTimeInSeconds) => Output(new Output.DoubleExpTimeStart(lengthOfTimeInSeconds));
private void OnGameEnded() => Output(new Output.ShowLostScreen());
public void OnIsPaused(bool isPaused) => Output(new Output.SetPauseMode(isPaused));
}
}

View File

@@ -1,13 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public interface IGameLogic : ILogicBlock<GameLogic.State>;
[Meta]
[LogicBlock(typeof(State), Diagram = true)]
public partial class GameLogic : LogicBlock<GameLogic.State>, IGameLogic
{
public override Transition GetInitialState() => To<State.MenuBackdrop>();
}

View File

@@ -0,0 +1,13 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public interface IGameState : ILogicBlock<GameState.State>;
[Meta]
[LogicBlock(typeof(State), Diagram = true)]
public partial class GameState : LogicBlock<GameState.State>, IGameState
{
public override Transition GetInitialState() => To<State.MainMenu>();
}

View File

@@ -0,0 +1,29 @@
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public static class Input
{
public readonly record struct NewGame;
public readonly record struct LoadGame;
public readonly record struct ContinueGame;
public readonly record struct ReturnToMainMenu;
public readonly record struct LoadNextFloor;
public readonly record struct InventoryButtonPressed;
public readonly record struct MiniMapButtonPressed;
public readonly record struct PauseButtonPressed;
public readonly record struct DebugButtonPressed;
public readonly record struct FloorExitEntered;
public readonly record struct GameOver;
}
}

View File

@@ -0,0 +1,33 @@
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public static class Output
{
public readonly record struct InitializeGame;
public readonly record struct LoadGameFromFile;
public readonly record struct OpenInventoryMenu;
public readonly record struct CloseInventoryMenu;
public readonly record struct OpenMiniMap;
public readonly record struct CloseMiniMap;
public readonly record struct OpenPauseScreen;
public readonly record struct ClosePauseScreen;
public readonly record struct LoadNextFloor;
public readonly record struct OpenFloorExitScreen;
public readonly record struct OpenDebugMenu;
public readonly record struct CloseDebugMenu;
public readonly record struct GameOver;
}
}

View File

@@ -0,0 +1,12 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
[Meta]
public abstract partial record State : StateLogic<State>
{
}
}

View File

@@ -0,0 +1,20 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record DebugMenu : State, IGet<Input.DebugButtonPressed>
{
public Transition On(in Input.DebugButtonPressed input)
{
Output(new Output.CloseDebugMenu());
return To<InGame>();
}
}
}
}

View File

@@ -0,0 +1,30 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record FloorExitScreen : State, IGet<Input.LoadNextFloor>, IGet<Input.ReturnToMainMenu>
{
public FloorExitScreen()
{
OnAttach(() => Get<IGameRepo>().Pause());
}
public Transition On(in Input.LoadNextFloor input)
{
Output(new Output.LoadNextFloor());
return To<InGame>();
}
public Transition On(in Input.ReturnToMainMenu input)
{
return To<MainMenu>();
}
}
}
}

View File

@@ -0,0 +1,25 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record GameOver : State, IGet<Input.ContinueGame>, IGet<Input.ReturnToMainMenu>
{
public Transition On(in Input.ContinueGame input)
{
Output(new Output.InitializeGame());
return To<InGame>();
}
public Transition On(in Input.ReturnToMainMenu input)
{
return To<MainMenu>();
}
}
}
}

View File

@@ -0,0 +1,56 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record InGame : State,
IGet<Input.InventoryButtonPressed>,
IGet<Input.MiniMapButtonPressed>,
IGet<Input.PauseButtonPressed>,
IGet<Input.DebugButtonPressed>,
IGet<Input.FloorExitEntered>,
IGet<Input.GameOver>
{
public Transition On(in Input.InventoryButtonPressed input)
{
Output(new Output.OpenInventoryMenu());
return To<InventoryScreen>();
}
public Transition On(in Input.MiniMapButtonPressed input)
{
Output(new Output.OpenMiniMap());
return To<MiniMapScreen>();
}
public Transition On(in Input.PauseButtonPressed input)
{
Output(new Output.OpenPauseScreen());
return To<PauseScreen>();
}
public Transition On(in Input.DebugButtonPressed input)
{
Output(new Output.OpenDebugMenu());
return To<DebugMenu>();
}
public Transition On(in Input.FloorExitEntered input)
{
Output(new Output.OpenFloorExitScreen());
return To<FloorExitScreen>();
}
public Transition On(in Input.GameOver input)
{
Output(new Output.GameOver());
return To<GameOver>();
}
}
}
}

View File

@@ -0,0 +1,20 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record InventoryScreen : State, IGet<Input.InventoryButtonPressed>
{
public Transition On(in Input.InventoryButtonPressed input)
{
Output(new Output.CloseInventoryMenu());
return To<InGame>();
}
}
}
}

View File

@@ -0,0 +1,33 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
using Zennysoft.Game.Abstractions;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record MainMenu : State, IGet<Input.NewGame>, IGet<Input.ContinueGame>, IGet<Input.LoadGame>
{
public Transition On(in Input.NewGame input)
{
Output(new Output.InitializeGame());
return To<InGame>();
}
public Transition On(in Input.ContinueGame input)
{
Output(new Output.InitializeGame());
return To<InGame>();
}
public Transition On(in Input.LoadGame input)
{
Output(new Output.LoadGameFromFile());
return To<InGame>();
}
}
}
}

View File

@@ -0,0 +1,20 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record MiniMapScreen : State, IGet<Input.MiniMapButtonPressed>
{
public Transition On(in Input.MiniMapButtonPressed input)
{
Output(new Output.CloseMiniMap());
return To<InGame>();
}
}
}
}

View File

@@ -0,0 +1,20 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameState
{
public partial record State
{
[Meta, LogicBlock(typeof(State), Diagram = true)]
public partial record PauseScreen : State, IGet<Input.PauseButtonPressed>
{
public Transition On(in Input.PauseButtonPressed input)
{
Output(new Output.ClosePauseScreen());
return To<InGame>();
}
}
}
}

View File

@@ -1,26 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record AskForTeleport : Playing, IGet<Input.FloorExitReached>, IGet<Input.HideAskForTeleport>
{
public AskForTeleport()
{
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowAskForTeleport()); });
this.OnDetach(() => { Output(new Output.HideAskForTeleport()); });
}
public Transition On(in Input.FloorExitReached input) => To<FloorClearedDecisionState>();
public Transition On(in Input.HideAskForTeleport input)
{
return To<Playing>();
}
}
}
}

View File

@@ -1,36 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record FloorClearedDecisionState : Playing, IGet<Input.GoToNextFloor>, IGet<Input.SaveGame>, IGet<Input.HideFloorClearMenu>
{
public FloorClearedDecisionState()
{
this.OnAttach(() => { Get<IGameRepo>().Pause(); Output(new Output.ShowFloorClearMenu()); });
this.OnDetach(() => { Output(new Output.ExitFloorClearMenu()); });
}
public Transition On(in Input.GoToNextFloor input)
{
Output(new Output.LoadNextFloor());
return ToSelf();
}
public Transition On(in Input.HideFloorClearMenu input)
{
return To<Playing>();
}
public Transition On(in Input.SaveGame input)
{
Output(new Output.SaveGame());
return To<Playing>();
}
}
}
}

View File

@@ -1,32 +0,0 @@
namespace Zennysoft.Ma.Adapter;
using Chickensoft.Introspection;
using Zennysoft.Game.Abstractions;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record MenuBackdrop : State, IGet<Input.StartGame>, IGet<Input.Initialize>
{
public MenuBackdrop()
{
OnAttach(() => Get<IAppRepo>().GameEntered += OnGameEntered);
OnDetach(() => Get<IAppRepo>().GameEntered -= OnGameEntered);
}
public void OnGameEntered() => Input(new Input.StartGame());
public Transition On(in Input.StartGame input)
{
return To<Playing>();
}
public Transition On(in Input.Initialize input)
{
return ToSelf();
}
}
}
}

View File

@@ -1,26 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record Paused : Playing, IGet<Input.UnpauseGame>
{
public Paused()
{
this.OnEnter(() =>
{
Get<IGameRepo>().Pause();
Output(new Output.ShowPauseMenu());
});
this.OnExit(() => Output(new Output.ExitPauseMenu()));
}
public virtual Transition On(in Input.UnpauseGame input) => To<Resuming>();
}
}
}

View File

@@ -1,37 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record Playing : State,
IGet<Input.AskForTeleport>,
IGet<Input.PauseGame>,
IGet<Input.GoToOverworld>
{
public Playing()
{
OnAttach(() =>
{
Output(new Output.StartGame());
Output(new Output.LoadMap());
});
}
public void OnEnded() => Input(new Input.GameOver());
public Transition On(in Input.AskForTeleport input) => To<AskForTeleport>();
public Transition On(in Input.PauseGame input) => To<Paused>();
public Transition On(in Input.GoToOverworld input)
{
Output(new Output.GoToOverworld());
return ToSelf();
}
}
}
}

View File

@@ -1,25 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Ma.Adapter;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record Quit : State, IGet<Input.GoToOverworld>
{
public Quit()
{
this.OnEnter(() => Output(new Output.ShowLostScreen()));
}
public Transition On(in Input.GoToOverworld input)
{
Input(new Input.StartGame());
return To<Playing>();
}
}
}
}

View File

@@ -1,23 +0,0 @@
namespace Zennysoft.Ma.Adapter;
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
public partial class GameLogic
{
public partial record State
{
[Meta]
public partial record Resuming : Playing, IGet<Input.PauseMenuTransitioned>
{
public Resuming()
{
this.OnEnter(() => Get<IGameRepo>().Resume());
this.OnExit(() => Output(new Output.HidePauseMenu()));
}
public Transition On(in Input.PauseMenuTransitioned input) =>
To<Playing>();
}
}
}