namespace GameJamDungeon; using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; using System; using static GameJamDungeon.GameLogic.State; [Meta(typeof(IAutoNode))] public partial class Game : Node3D, IGame { public override void _Notification(int what) => this.Notify(what); IGameRepo IProvide.Value() => GameRepo; IGame IProvide.Value() => this; IPlayer IProvide.Value() => Player; IGameEventDepot IProvide.Value() => GameEventDepot; public IInstantiator Instantiator { get; set; } = default!; public IGameLogic GameLogic { get; set; } = default!; public IGameEventDepot GameEventDepot { get; set; } = default!; public IGameRepo GameRepo { get; set; } = default!; public GameLogic.IBinding GameBinding { get; set; } = default!; [Signal] public delegate void StatRaisedAlertEventHandler(string statRaisedAlert); [Dependency] public IAppRepo AppRepo => this.DependOn(); #region Nodes [Node] private IMap Map { get; set; } = default!; [Node] private InGameUI InGameUI { get; set; } = default!; [Node] private IFloorClearMenu FloorClearMenu { get; set; } = default!; [Node] private DeathMenu DeathMenu { get; set; } = default!; [Node] private IPauseMenu PauseMenu { get; set; } = default!; [Node] private InGameAudio InGameAudio { get; set; } = default!; [Node] private Timer DoubleEXPTimer { get; set; } = default!; [Node] private IPlayer Player { get; set; } = default!; #endregion public RescuedItemDatabase RescuedItems { get; set; } = default!; public void Setup() { GameRepo = new GameRepo(); GameLogic = new GameLogic(); GameEventDepot = new GameEventDepot(); GameLogic.Set(GameRepo); GameLogic.Set(AppRepo); GameLogic.Set(GameEventDepot); GameLogic.Set(Player); Instantiator = new Instantiator(GetTree()); RescuedItems = new RescuedItemDatabase(); } public void OnResolved() { GameBinding = GameLogic.Bind(); GameBinding .Handle((in GameLogic.Output.StartGame _) => { InGameUI.Show(); }) .Handle((in GameLogic.Output.GoToOverworld _) => { GameEventDepot.OnOverworldEntered(); }) .Handle((in GameLogic.Output.SetPauseMode output) => CallDeferred(nameof(SetPauseMode), output.IsPaused)) .Handle((in GameLogic.Output.ShowPauseMenu _) => { PauseMenu.Show(); PauseMenu.FadeIn(); Input.MouseMode = Input.MouseModeEnum.Visible; PauseMenu.SetProcessUnhandledInput(true); }) .Handle((in GameLogic.Output.LoadNextFloor _) => { Map.SpawnNextFloor(); }) .Handle((in GameLogic.Output.HidePauseMenu _) => { PauseMenu.Hide(); }) .Handle((in GameLogic.Output.ExitPauseMenu _) => { PauseMenu.FadeOut(); Input.MouseMode = Input.MouseModeEnum.Visible; PauseMenu.SetProcessUnhandledInput(false); }) .Handle((in GameLogic.Output.ShowFloorClearMenu _) => { FloorClearMenu.Show(); FloorClearMenu.FadeIn(); }) .Handle((in GameLogic.Output.ExitFloorClearMenu _) => { FloorClearMenu.FadeOut(); }) .Handle((in GameLogic.Output.OpenInventory _) => { InGameUI.ShowInventoryScreen(); InGameUI.InventoryMenu.SetProcessInput(true); }) .Handle((in GameLogic.Output.HideInventory _) => { InGameUI.HideInventoryScreen(); InGameUI.InventoryMenu.SetProcessInput(false); }) .Handle((in GameLogic.Output.ShowMiniMap _) => { InGameUI.ShowMiniMap(); }) .Handle((in GameLogic.Output.HideMiniMap _) => { InGameUI.HideMiniMap(); }) .Handle((in GameLogic.Output.ShowAskForTeleport _) => { GameRepo.Pause(); InGameUI.UseTeleportPrompt.FadeIn(); InGameUI.SetProcessInput(true); }) .Handle((in GameLogic.Output.HideAskForTeleport _) => { GameRepo.Resume(); InGameUI.UseTeleportPrompt.FadeOut(); InGameUI.SetProcessInput(false); }) .Handle((in GameLogic.Output.ShowLostScreen _) => { DeathMenu.Show(); DeathMenu.FadeIn(); }) .Handle((in GameLogic.Output.ExitLostScreen _) => { DeathMenu.FadeOut(); }); GameLogic.Start(); GameLogic.Input(new GameLogic.Input.Initialize()); this.Provide(); PauseMenu.TransitionCompleted += OnPauseMenuTransitioned; PauseMenu.UnpauseButtonPressed += PauseMenu_UnpauseButtonPressed; InGameUI.InventoryMenu.ClosedMenu += InventoryMenu_CloseInventory; InGameUI.MinimapButtonReleased += Player_MinimapButtonReleased; InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor; InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt; Player.Inventory.InventoryAtCapacity += PlayerInventory_InventoryAtCapacity; Player.Inventory.PickedUpItem += Inventory_PickedUpItem; FloorClearMenu.GoToNextFloor += FloorClearMenu_GoToNextFloor; FloorClearMenu.SaveAndExit += FloorClearMenu_SaveAndExit; FloorClearMenu.TransitionCompleted += FloorClearMenu_TransitionCompleted; GameEventDepot.RestorativePickedUp += GameEventDepot_RestorativePickedUp; DoubleEXPTimer.Timeout += DoubleEXPTimer_Timeout; } public void ToggleInventory() { if (GameLogic.Value is InventoryOpened) GameLogic.Input(new GameLogic.Input.CloseInventory()); else GameLogic.Input(new GameLogic.Input.OpenInventory()); } public void ToggleMinimap() { GameLogic.Input(new GameLogic.Input.MiniMapButtonPressed()); } public void FloorExitReached() { GameLogic.Input(new GameLogic.Input.AskForTeleport()); GameEventDepot.OnTeleportEntered(); } private void Inventory_PickedUpItem(string pickedUpItemName) { InGameUI.PlayerInfoUI.DisplayMessage($"{pickedUpItemName} picked up."); } public void DropItem(IInventoryItem item) { var droppedScene = GD.Load("res://src/items/dropped/DroppedItem.tscn"); var dropped = droppedScene.Instantiate(); dropped.Item = item; AddChild(dropped); dropped.Drop(); } public void ThrowItem(IInventoryItem item) { var thrownScene = GD.Load("res://src/items/thrown/ThrownItem.tscn"); var thrown = thrownScene.Instantiate(); thrown.ItemThatIsThrown = item; AddChild(thrown); thrown.Position += new Vector3(-0.5f, 1.5f, -0.5f); thrown.Throw(); } public void AnnounceMessageOnInventoryScreen(string message) { InGameUI.InventoryMenu.ShowMessage(message); } public void AnnounceMessageOnMainScreen(string message) { InGameUI.PlayerInfoUI.DisplayMessage(message); } public IDungeonFloor CurrentFloor => Map.CurrentFloor; public void EnemyDefeated(Vector3 defeatedLocation, EnemyStatResource resource) { Player.GainExp(resource.ExpFromDefeat * GameRepo.EXPRate); } private void DropRestorative(Vector3 vector) { var restorativeScene = GD.Load("res://src/items/restorative/Restorative.tscn"); var restorative = restorativeScene.Instantiate(); AddChild(restorative); restorative.GlobalPosition = vector; } private void UseTeleportPrompt_CloseTeleportPrompt() { GameLogic.Input(new GameLogic.Input.HideAskForTeleport()); } private void UseTeleportPrompt_TeleportToNextFloor() { GameLogic.Input(new GameLogic.Input.FloorExitReached()); GameEventDepot.OnDungeonAThemeAreaEntered(); } private void PauseMenu_UnpauseButtonPressed() { GameLogic.Input(new GameLogic.Input.UnpauseGame()); } private void Player_PauseButtonPressed() { GameLogic.Input(new GameLogic.Input.PauseGame()); } private void Player_MinimapButtonReleased() { GameLogic.Input(new GameLogic.Input.MiniMapButtonReleased()); } private void FloorClearMenu_TransitionCompleted() { GameRepo.Resume(); if (Player.EquippedWeapon.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) Player.Unequip(Player.EquippedWeapon.Value); if (Player.EquippedArmor.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) Player.Unequip(Player.EquippedArmor.Value); if (Player.EquippedAccessory.Value.ItemTags.Contains(ItemTag.BreaksOnChange)) Player.Unequip(Player.EquippedAccessory.Value); } private void FloorClearMenu_GoToNextFloor() { GameLogic.Input(new GameLogic.Input.GoToNextFloor()); } private void FloorClearMenu_SaveAndExit() { // Save GameLogic.Input(new GameLogic.Input.HideFloorClearMenu()); GameLogic.Input(new GameLogic.Input.SaveGame()); } private void GameEventDepot_RestorativePickedUp(Restorative obj) => Player.Stats.SetCurrentVT(Player.Stats.CurrentVT.Value + obj.VTRestoreAmount); private void SetPauseMode(bool isPaused) { if (GetTree() != null) GetTree().Paused = isPaused; } public async void DoubleEXP(TimeSpan lengthOfEffect) { ToggleInventory(); InGameUI.PlayerInfoUI.DisplayMessage("Experience points temporarily doubled."); DoubleEXPTimer.Start(lengthOfEffect.Seconds); GameRepo.EXPRate = 2; } private void DoubleEXPTimer_Timeout() { DoubleEXPTimer.Stop(); GameRepo.EXPRate = 1; InGameUI.PlayerInfoUI.DisplayMessage("Experience points effect wore off."); } private void PlayerInventory_InventoryAtCapacity(string rejectedItem) { InGameUI.PlayerInfoUI.DisplayMessage($"Could not pick up {rejectedItem}."); } private void InventoryMenu_CloseInventory() => GameLogic.Input(new GameLogic.Input.CloseInventory()); public void NextFloorLoaded() { GameLogic.Input(new GameLogic.Input.HideFloorClearMenu()); } private void OnPauseMenuTransitioned() { GameLogic.Input(new GameLogic.Input.PauseMenuTransitioned()); } public void OnStart() => GameLogic.Input(new GameLogic.Input.StartGame()); }