namespace GameJamDungeon; using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; public interface IGame : IProvide, IProvide, IProvide, INode3D { event Game.StatRaisedAlertEventHandler StatRaisedAlert; public IPlayer Player { get; } public void DropItem(IInventoryItem item); public void ThrowItem(IInventoryItem item); public void HealHP(int amountToRaise); public void RaiseHP(int amountToRaise); public void HealVT(int amountToRaise); public void RaiseVT(int amountToRaise); } [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; 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] public IMap Map { get; set; } = default!; [Node] public IPlayer Player { get; set; } = default!; [Node] public InGameUI InGameUI { get; set; } = default!; [Node] public IFloorClearMenu FloorClearMenu { get; set; } = default!; [Node] public DeathMenu DeathMenu { get; set; } = default!; [Node] public IPauseMenu PauseMenu { get; set; } = default!; [Node] public InGameAudio InGameAudio { get; set; } = default!; #endregion public void Setup() { GameRepo = new GameRepo(); GameLogic = new GameLogic(); GameEventDepot = new GameEventDepot(); GameLogic.Set(GameRepo); GameLogic.Set(AppRepo); GameLogic.Set(GameEventDepot); Instantiator = new Instantiator(GetTree()); } 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; GameEventDepot.TeleportEntered += Map_TeleportReached; Map.DungeonFinishedGenerating += Map_DungeonFinishedGenerating; InGameUI.InventoryMenu.ClosedMenu += InventoryMenu_CloseInventory; InGameUI.MinimapButtonReleased += Player_MinimapButtonReleased; InGameUI.UseTeleportPrompt.TeleportToNextFloor += UseTeleportPrompt_TeleportToNextFloor; InGameUI.UseTeleportPrompt.CloseTeleportPrompt += UseTeleportPrompt_CloseTeleportPrompt; GameRepo.PlayerData.Inventory.InventoryAtCapacity += PlayerInventory_InventoryAtCapacity; GameRepo.PlayerData.Inventory.PickedUpItem += Inventory_PickedUpItem; GameRepo.PlayerData.Inventory.RaiseStatRequest += Inventory_RaiseStatRequest; FloorClearMenu.GoToNextFloor += FloorClearMenu_GoToNextFloor; FloorClearMenu.ReturnToHubWorld += ReturnToHubWorld; FloorClearMenu.TransitionCompleted += FloorClearMenu_TransitionCompleted; Player.InventoryButtonPressed += Player_InventoryButtonPressed; Player.MinimapButtonHeld += Player_MinimapButtonHeld; Player.PauseButtonPressed += Player_PauseButtonPressed; GameEventDepot.EnemyDefeated += OnEnemyDefeated; GameEventDepot.RestorativePickedUp += GameEventDepot_RestorativePickedUp; } private void Inventory_PickedUpItem(string pickedUpItemName) { InGameUI.PlayerInfoUI.DisplayPickedUpMessage(pickedUpItemName); } 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.ThrownItemStats = item.Info; AddChild(thrown); thrown.Throw(); } private void OnEnemyDefeated(Vector3 vector, EnemyStatResource resource) { 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 Player_MinimapButtonHeld() { GameLogic.Input(new GameLogic.Input.MiniMapButtonPressed()); } private void Player_InventoryButtonPressed() { GameLogic.Input(new GameLogic.Input.OpenInventory()); } private void FloorClearMenu_TransitionCompleted() { GameRepo.Resume(); if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.BreaksOnChange)) GameRepo.PlayerData.Inventory.Unequip(GameRepo.PlayerData.Inventory.EquippedWeapon.Value); } private void FloorClearMenu_GoToNextFloor() { GameLogic.Input(new GameLogic.Input.GoToNextFloor()); } private void ReturnToHubWorld() { // Implement a return to overworld state // Don't carry over stats/equipment but we'll need to persist the overworld state // Which may include rescued items and npc/questline state GameLogic.Input(new GameLogic.Input.HideFloorClearMenu()); } private void GameEventDepot_RestorativePickedUp(Restorative obj) => GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + obj.VTRestoreAmount); private void Inventory_RaiseStatRequest(InventoryItemStats itemStats) { //if (itemStats.RaiseHPAmount > 0 && GameRepo.PlayerData.CurrentHP.Value.Equals(GameRepo.PlayerData.MaximumHP.Value)) // RaiseHP(itemStats.RaiseHPAmount); //else if (itemStats.HealHPAmount > 0) HealHP(itemStats.HealHPAmount); HealVT(itemStats.HealVTAmount); //if (itemStats.RaiseVTAmount > 0 && GameRepo.PlayerData.CurrentVT.Value.Equals(GameRepo.PlayerData.MaximumVT.Value)) // RaiseVT(itemStats.RaiseVTAmount); //else if (itemStats.HealVTAmount > 0) } private void SetPauseMode(bool isPaused) { if (GetTree() != null) GetTree().Paused = isPaused; } public void RaiseHP(int amountToRaise) { if (GameRepo.PlayerData.CurrentHP.Value == GameRepo.PlayerData.MaximumHP.Value) { GameRepo.PlayerData.SetMaximumHP(GameRepo.PlayerData.MaximumHP.Value + amountToRaise); GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.MaximumHP.Value); EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}MAXHP Up."); } } public void HealHP(int amountToRaise) { GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value + amountToRaise); var raiseString = amountToRaise == 1000 ? "MAX" : $"{amountToRaise}"; EmitSignal(SignalName.StatRaisedAlert, $"{raiseString}HP Restored."); } public void RaiseVT(int amountToRaise) { if (GameRepo.PlayerData.CurrentVT.Value == GameRepo.PlayerData.MaximumVT.Value) { GameRepo.PlayerData.SetMaximumVT(GameRepo.PlayerData.MaximumVT.Value + amountToRaise); GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.MaximumVT.Value); EmitSignal(SignalName.StatRaisedAlert, $"{amountToRaise}MAXVT Up."); } } public void HealVT(int amountToRaise) { GameRepo.PlayerData.SetCurrentVT(GameRepo.PlayerData.CurrentVT.Value + amountToRaise); var raiseString = amountToRaise == 1000 ? "MAX" : $"{amountToRaise}"; EmitSignal(SignalName.StatRaisedAlert, $"{raiseString}VT Restored."); } private void PlayerInventory_InventoryAtCapacity(string rejectedItem) { InGameUI.PlayerInfoUI.DisplayInventoryFullMessage(rejectedItem); } private void OnInventoryAtCapacity(string rejectedItemName) => InGameUI.PlayerInfoUI.DisplayInventoryFullMessage(rejectedItemName); private void InventoryMenu_CloseInventory() => GameLogic.Input(new GameLogic.Input.CloseInventory()); private void Map_DungeonFinishedGenerating() { var transform = Map.GetPlayerSpawnPosition(); GameRepo.SetPlayerGlobalPosition(transform.Origin); GameRepo.SetPlayerGlobalTransform(transform); GameLogic.Input(new GameLogic.Input.HideFloorClearMenu()); } private void Map_TeleportReached() { GameLogic.Input(new GameLogic.Input.AskForTeleport()); } private void OnPauseMenuTransitioned() { GameLogic.Input(new GameLogic.Input.PauseMenuTransitioned()); } public void OnStart() => GameLogic.Input(new GameLogic.Input.StartGame()); }