diff --git a/Zennysoft.Game.Ma.Implementation/App/State/AppLogic.Output.cs b/Zennysoft.Game.Ma.Implementation/App/State/AppLogic.Output.cs index bbfcfb48..b91d3bad 100644 --- a/Zennysoft.Game.Ma.Implementation/App/State/AppLogic.Output.cs +++ b/Zennysoft.Game.Ma.Implementation/App/State/AppLogic.Output.cs @@ -24,6 +24,8 @@ public partial class AppLogic public readonly record struct ShowMainMenu; + public readonly record struct CloseGame; + public readonly record struct ExitGame; public readonly record struct GameOver; diff --git a/Zennysoft.Game.Ma.Implementation/App/State/States/AppLogic.State.GameStarted.cs b/Zennysoft.Game.Ma.Implementation/App/State/States/AppLogic.State.GameStarted.cs index 2dde0f39..816073d2 100644 --- a/Zennysoft.Game.Ma.Implementation/App/State/States/AppLogic.State.GameStarted.cs +++ b/Zennysoft.Game.Ma.Implementation/App/State/States/AppLogic.State.GameStarted.cs @@ -9,7 +9,7 @@ public partial class AppLogic public partial record State { [Meta] - public partial record GameStarted : State + public partial record GameStarted : State, IGet { public GameStarted() { @@ -26,6 +26,11 @@ public partial class AppLogic OnDetach(() => Get().GameExited -= OnGameExited); } + public Transition On(in Input.QuitGame input) + { + Output(new Output.CloseGame()); + return To(); + } public void OnGameExited() => Input(new Input.QuitGame()); } } diff --git a/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Input.cs b/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Input.cs index bce07db5..13e5f30b 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Input.cs +++ b/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Input.cs @@ -8,10 +8,14 @@ public partial class GameState public readonly record struct LoadGame; + public readonly record struct ExitGame; + public readonly record struct LoadNextFloor; public readonly record struct InventoryButtonPressed; + public readonly record struct InteractButtonPressed; + public readonly record struct PauseButtonPressed; public readonly record struct DebugButtonPressed; diff --git a/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Output.cs b/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Output.cs index dfbfc140..774a2244 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Output.cs +++ b/Zennysoft.Game.Ma.Implementation/Game/state/GameState.Output.cs @@ -6,6 +6,8 @@ public partial class GameState { public readonly record struct InitializeGame; + public readonly record struct ExitGame; + public readonly record struct LoadGameFromFile; public readonly record struct OpenInventoryMenu; diff --git a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.InventoryScreen..cs b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.InventoryScreen..cs index 139a72f9..fc4f68bb 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.InventoryScreen..cs +++ b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.InventoryScreen..cs @@ -8,9 +8,9 @@ public partial class GameState public partial record State { [Meta, LogicBlock(typeof(State), Diagram = true)] - public partial record InventoryScreen : State, IGet + public partial record InventoryScreen : State, IGet { - public Transition On(in Input.InventoryButtonPressed input) + public Transition On(in Input.InteractButtonPressed input) { Output(new Output.CloseInventoryMenu()); return To(); diff --git a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.PauseScreen..cs b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.PauseScreen..cs index 18b4a9a9..4ced8694 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.PauseScreen..cs +++ b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.PauseScreen..cs @@ -1,5 +1,6 @@ using Chickensoft.Introspection; using Chickensoft.LogicBlocks; +using static Zennysoft.Ma.Adapter.GameState.Output; namespace Zennysoft.Ma.Adapter; @@ -8,13 +9,20 @@ public partial class GameState public partial record State { [Meta, LogicBlock(typeof(State), Diagram = true)] - public partial record PauseScreen : State, IGet + public partial record PauseScreen : State, IGet, IGet { public Transition On(in Input.PauseButtonPressed input) { Output(new Output.ClosePauseScreen()); return To(); } + + public Transition On(in Input.ExitGame input) + { + Output(new Output.ClosePauseScreen()); + Output(new Output.ExitGame()); + return To(); + } } } } diff --git a/Zennysoft.Game.Ma/src/app/App.cs b/Zennysoft.Game.Ma/src/app/App.cs index 54519c46..236c07f1 100644 --- a/Zennysoft.Game.Ma/src/app/App.cs +++ b/Zennysoft.Game.Ma/src/app/App.cs @@ -1,20 +1,14 @@ using Chickensoft.AutoInject; -using Chickensoft.Collections; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; -using Godot.Collections; using NathanHoad; using SimpleInjector.Lifestyles; -using System; using System.IO.Abstractions; -using System.Linq; using System.Threading.Tasks; using Zennysoft.Game.Abstractions; using Zennysoft.Game.Implementation; using Zennysoft.Ma.Adapter; -using static Zennysoft.Game.Ma.SceneLoader; -using static Zennysoft.Ma.Adapter.AppLogic.State; namespace Zennysoft.Game.Ma; @@ -37,8 +31,6 @@ public partial class App : Node, IApp [Node] private GalleryMenu GalleryMenu { get; set; } - public IInstantiator Instantiator { get; set; } = default!; - IAppRepo IProvide.Value() => AppRepo; public IAppRepo AppRepo { get; set; } = default!; @@ -57,9 +49,6 @@ public partial class App : Node, IApp private IGame _game; private IDataViewer _enemyViewer; - private event Action OnGameLoaded; - private event Action OnEnemyViewerLoaded; - private double _reportedProgress = 0; public void Initialize() @@ -110,6 +99,11 @@ public partial class App : Node, IApp this.Provide(); } + private void GameExitRequested() + { + AppLogic.Input(new AppLogic.Input.QuitGame()); + } + private void DeleteSaveData() { var saveFileManager = _container.GetInstance(); @@ -150,27 +144,31 @@ public partial class App : Node, IApp }) .Handle((in AppLogic.Output.SetupGameScene _) => { + LoadingScreen.Show(); LoadGame(GAME_SCENE_PATH); - MainMenu.ReleaseFocus(); - MainMenu.Hide(); }) .Handle((in AppLogic.Output.ShowMainMenu _) => { }) - .Handle((in AppLogic.Output.ShowGame _) => + .Handle((in AppLogic.Output.CloseGame _) => { + LoadingScreen.Hide(); + _game.GameExitRequested -= GameExitRequested; + MainMenu.StartGameButton.GrabFocus(); + _game.CallDeferred(MethodName.QueueFree, []); + GetTree().Paused = false; }) .Handle((in AppLogic.Output.StartLoadingSaveFile _) => { }) .Handle((in AppLogic.Output.EnemyViewerOpened _) => { + LoadingScreen.Show(); LoadEnemyViewer(ENEMY_VIEWER_PATH); - MainMenu.ReleaseFocus(); - MainMenu.Hide(); }) .Handle((in AppLogic.Output.EnemyViewerExited _) => { + LoadingScreen.Hide(); if (_enemyViewer != null && _enemyViewer is DataViewer enemyViewer) enemyViewer.CallDeferred(MethodName.QueueFree); MainMenu.Show(); @@ -202,6 +200,7 @@ public partial class App : Node, IApp { var scene = await LoadSceneInternal(sceneName); _game = scene as IGame; + _game.GameExitRequested += GameExitRequested; await ToSignal(GetTree().CreateTimer(0.8f), "timeout"); CallDeferred(MethodName.AddChild, scene); } @@ -216,6 +215,7 @@ public partial class App : Node, IApp private async Task LoadSceneInternal(string sceneName) { + LoadingScreen.Show(); LoadingScreen.ProgressBar.Value = 0; var sceneLoader = new SceneLoader(); CallDeferred(MethodName.AddChild, sceneLoader); diff --git a/Zennysoft.Game.Ma/src/app/App.tscn b/Zennysoft.Game.Ma/src/app/App.tscn index c236d552..1a054326 100644 --- a/Zennysoft.Game.Ma/src/app/App.tscn +++ b/Zennysoft.Game.Ma/src/app/App.tscn @@ -10,12 +10,13 @@ process_mode = 3 script = ExtResource("1_rt73h") -[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")] -unique_name_in_owner = true - [node name="MainMenu" parent="." instance=ExtResource("2_1uiag")] unique_name_in_owner = true +[node name="LoadingScreen" parent="." instance=ExtResource("3_3st5l")] +unique_name_in_owner = true +visible = false + [node name="OptionsMenu" parent="." instance=ExtResource("2_v0mgf")] unique_name_in_owner = true visible = false diff --git a/Zennysoft.Game.Ma/src/game/Game.cs b/Zennysoft.Game.Ma/src/game/Game.cs index 4704b66d..e7c3ae82 100644 --- a/Zennysoft.Game.Ma/src/game/Game.cs +++ b/Zennysoft.Game.Ma/src/game/Game.cs @@ -56,6 +56,8 @@ public partial class Game : Node3D, IGame [Signal] public delegate void SaveFileLoadedEventHandler(); + + public event Action GameExitRequested; #endregion public RescuedItemDatabase RescuedItems { get; set; } = default!; @@ -174,6 +176,8 @@ public partial class Game : Node3D, IGame GameOverMenu.NewGame += OnNewGame; GameOverMenu.QuitGame += OnQuit; + PauseMenu.ExitGamePressed += OnQuit; + GameRepo.IsPaused.Sync += IsPaused_Sync; InGameUI.PlayerInfoUI.Activate(); } @@ -252,6 +256,12 @@ public partial class Game : Node3D, IGame { if (@event.IsActionPressed(GameInputs.Debug)) GameState.Input(new GameState.Input.DebugButtonPressed()); + if (@event.IsActionPressed(GameInputs.Pause)) + GameState.Input(new GameState.Input.PauseButtonPressed()); + if (Input.IsActionJustPressed(GameInputs.Inventory)) + GameState.Input(new GameState.Input.InventoryButtonPressed()); + if (Input.IsActionJustPressed(GameInputs.Interact)) + GameState.Input(new GameState.Input.InteractButtonPressed()); } private void HandleGameLogic() @@ -280,12 +290,13 @@ public partial class Game : Node3D, IGame }) .Handle((in GameState.Output.OpenInventoryMenu _) => { - //InGameUI.InventoryMenu.RefreshInventoryScreen(); + GameRepo.Pause(); InGameUI.InventoryMenu.Show(); InGameUI.InventoryMenu.SetProcessInput(true); }) .Handle((in GameState.Output.CloseInventoryMenu _) => { + GameRepo.Resume(); InGameUI.InventoryMenu.Hide(); InGameUI.InventoryMenu.SetProcessInput(false); }) @@ -337,6 +348,10 @@ public partial class Game : Node3D, IGame } LoadNextLevel.FadeOut(); }) + .Handle((in GameState.Output.ExitGame _) => + { + OnQuit(); + }) .Handle((in GameState.Output.GameOver _) => { //GameRepo.Pause(); @@ -507,7 +522,7 @@ public partial class Game : Node3D, IGame LoadNextLevel.Hide(); } - private void OnQuit() => GetTree().Root.QueueFree(); + private void OnQuit() => GameExitRequested?.Invoke(); public void OnExitTree() { diff --git a/Zennysoft.Game.Ma/src/game/IGame.cs b/Zennysoft.Game.Ma/src/game/IGame.cs index 607637b5..8e70a850 100644 --- a/Zennysoft.Game.Ma/src/game/IGame.cs +++ b/Zennysoft.Game.Ma/src/game/IGame.cs @@ -4,6 +4,7 @@ namespace Zennysoft.Game.Ma; using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; using Chickensoft.SaveFileBuilder; +using System; using System.Threading.Tasks; using Zennysoft.Ma.Adapter; @@ -30,4 +31,6 @@ public interface IGame : IProvide, IProvide, IProvide public Task Save(); public QuestData QuestData { get; } + + public event Action GameExitRequested; } diff --git a/Zennysoft.Game.Ma/src/menu/DebugMenu.tscn b/Zennysoft.Game.Ma/src/menu/DebugMenu.tscn index d51cd105..2da087fd 100644 --- a/Zennysoft.Game.Ma/src/menu/DebugMenu.tscn +++ b/Zennysoft.Game.Ma/src/menu/DebugMenu.tscn @@ -7,6 +7,7 @@ [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1ctjd"] [node name="Control" type="Control"] +process_mode = 3 layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 diff --git a/Zennysoft.Game.Ma/src/player/Player.cs b/Zennysoft.Game.Ma/src/player/Player.cs index 1a83a490..0094f7a7 100644 --- a/Zennysoft.Game.Ma/src/player/Player.cs +++ b/Zennysoft.Game.Ma/src/player/Player.cs @@ -107,187 +107,187 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide public void Initialize() { - var container = new SimpleInjector.Container(); - container.Register(Lifestyle.Singleton); + var container = new SimpleInjector.Container(); + container.Register(Lifestyle.Singleton); - PlayerLogic = container.GetInstance(); - PlayerLogic.Set(this as IPlayer); - PlayerLogic.Set(Settings); + PlayerLogic = container.GetInstance(); + PlayerLogic.Set(this as IPlayer); + PlayerLogic.Set(Settings); - Inventory = new Inventory(); - HealthComponent = new HealthComponent(InitialHP); - VTComponent = new VTComponent(InitialVT); - AttackComponent = new AttackComponent(InitialAttack); - DefenseComponent = new DefenseComponent(InitialDefense); - ExperiencePointsComponent = new ExperiencePointsComponent(); - LuckComponent = new LuckComponent(InitialLuck); - EquipmentComponent = new EquipmentComponent(); + Inventory = new Inventory(); + HealthComponent = new HealthComponent(InitialHP); + VTComponent = new VTComponent(InitialVT); + AttackComponent = new AttackComponent(InitialAttack); + DefenseComponent = new DefenseComponent(InitialDefense); + ExperiencePointsComponent = new ExperiencePointsComponent(); + LuckComponent = new LuckComponent(InitialLuck); + EquipmentComponent = new EquipmentComponent(); - _itemReroller = new ItemReroller(ItemDatabase.Instance); + _itemReroller = new ItemReroller(ItemDatabase.Instance); - Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration }; + Settings = new PlayerLogic.Settings() { RotationSpeed = RotationSpeed, MoveSpeed = MoveSpeed, Acceleration = Acceleration }; - PlayerBinding = PlayerLogic.Bind(); + PlayerBinding = PlayerLogic.Bind(); - PlayerBinding - .Handle((in PlayerLogic.Output.ThrowItem output) => - { - }) - .Handle((in PlayerLogic.Output.Move output) => - { - Move(output.delta); - }); + PlayerBinding + .Handle((in PlayerLogic.Output.ThrowItem output) => + { + }) + .Handle((in PlayerLogic.Output.Move output) => + { + Move(output.delta); + }); - PlayerLogic.Start(); - this.Provide(); + PlayerLogic.Start(); + this.Provide(); } public void ResetPlayerData() { - foreach (var item in Inventory.Items) - Inventory.Remove(item); + foreach (var item in Inventory.Items) + Inventory.Remove(item); - HealthComponent.Reset(); - VTComponent.Reset(); - AttackComponent.Reset(); - DefenseComponent.Reset(); - ExperiencePointsComponent.Reset(); - LuckComponent.Reset(); - EquipmentComponent.Reset(); + HealthComponent.Reset(); + VTComponent.Reset(); + AttackComponent.Reset(); + DefenseComponent.Reset(); + ExperiencePointsComponent.Reset(); + LuckComponent.Reset(); + EquipmentComponent.Reset(); - HealthTimer.Timeout += OnHealthTimerTimeout; + HealthTimer.Timeout += OnHealthTimerTimeout; } #region Initialization public void OnReady() { - Hitbox.AreaEntered += Hitbox_AreaEntered; - CollisionDetector.AreaEntered += CollisionDetector_AreaEntered; - HealthComponent.HealthReachedZero += Die; - HealthTimer.WaitTime = _healthTimerWaitTime; - SetProcessInput(false); - SetPhysicsProcess(false); + Hitbox.AreaEntered += Hitbox_AreaEntered; + CollisionDetector.AreaEntered += CollisionDetector_AreaEntered; + HealthComponent.HealthReachedZero += Die; + HealthTimer.WaitTime = _healthTimerWaitTime; + SetProcessInput(false); + SetPhysicsProcess(false); } #endregion public void Activate() { - SetProcessInput(true); - SetPhysicsProcess(true); - SetHealthTimerStatus(HealthTimerIsActive); + SetProcessInput(true); + SetPhysicsProcess(true); + SetHealthTimerStatus(HealthTimerIsActive); } public void Deactivate() { - Velocity = Vector3.Zero; - SetProcessInput(false); - SetPhysicsProcess(false); - SetHealthTimerStatus(false); + Velocity = Vector3.Zero; + SetProcessInput(false); + SetPhysicsProcess(false); + SetHealthTimerStatus(false); } private void SetHealthTimerStatus(bool isActive) { - if (isActive) - HealthTimer.Start(); - else - HealthTimer.Stop(); + if (isActive) + HealthTimer.Start(); + else + HealthTimer.Stop(); } public void TeleportPlayer(Transform3D newTransform) { - Transform = newTransform; + Transform = newTransform; } public void TakeDamage(AttackData damage) { - _camera3D.AddShake(1.0f); - TakeDamageAnimationPlayer.Play("take_damage"); - var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance); - HealthComponent.Damage(damageReceived); - SfxDatabase.Instance.Play(SoundEffect.TakeDamage); + _camera3D.AddShake(1.0f); + TakeDamageAnimationPlayer.Play("take_damage"); + var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance); + HealthComponent.Damage(damageReceived); + SfxDatabase.Instance.Play(SoundEffect.TakeDamage); } public void Knockback(float impulse) { - _knockbackStrength = impulse; - _knockbackDirection = GlobalBasis.Z.Normalized(); + _knockbackStrength = impulse; + _knockbackDirection = GlobalBasis.Z.Normalized(); } public void LevelUp() { - var rng = new RandomNumberGenerator(); - rng.Randomize(); - var hpIncrease = rng.RandiRange(3, 6); - HealthComponent.RaiseMaximumHP(hpIncrease); - ExperiencePointsComponent.LevelUp(); + var rng = new RandomNumberGenerator(); + rng.Randomize(); + var hpIncrease = rng.RandiRange(3, 6); + HealthComponent.RaiseMaximumHP(hpIncrease); + ExperiencePointsComponent.LevelUp(); } public void Die() { - PlayerFXAnimations.Play("death"); - HealthTimer.WaitTime = _healthTimerWaitTime; - HealthTimer.Timeout -= OnHealthTimerTimeout; - SetProcessInput(false); - SetPhysicsProcess(false); - PlayerDied?.Invoke(); + PlayerFXAnimations.Play("death"); + HealthTimer.WaitTime = _healthTimerWaitTime; + HealthTimer.Timeout -= OnHealthTimerTimeout; + SetProcessInput(false); + SetPhysicsProcess(false); + PlayerDied?.Invoke(); } public override void _Input(InputEvent @event) { - if (@event.IsActionPressed(GameInputs.Attack)) - Attack(); - if (@event.IsActionPressed(GameInputs.Sprint)) - Settings.MoveSpeed *= 2; - if (@event.IsActionReleased(GameInputs.Sprint)) - Settings.MoveSpeed /= 2; + if (@event.IsActionPressed(GameInputs.Attack)) + Attack(); + if (@event.IsActionPressed(GameInputs.Sprint)) + Settings.MoveSpeed *= 2; + if (@event.IsActionReleased(GameInputs.Sprint)) + Settings.MoveSpeed /= 2; } public void PlayTestAnimation() { - PlayerFXAnimations.Play("test_animation"); + PlayerFXAnimations.Play("test_animation"); } public void OnPhysicsProcess(double delta) { - PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta)); - PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform)); + PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta)); + PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform)); } public void Equip(EquipableItem equipable) { - if (equipable.ItemTag == ItemTag.MysteryItem) - { - var rerolledItem = _itemReroller.RerollItem(equipable, Inventory); - Equip(rerolledItem); - return; - } + if (equipable.ItemTag == ItemTag.MysteryItem) + { + var rerolledItem = _itemReroller.RerollItem(equipable, Inventory); + Equip(rerolledItem); + return; + } - HealthComponent.RaiseMaximumHP(equipable.BonusHP, false); - VTComponent.RaiseMaximumVT(equipable.BonusVT, false); + HealthComponent.RaiseMaximumHP(equipable.BonusHP, false); + VTComponent.RaiseMaximumVT(equipable.BonusVT, false); - EquipmentComponent.Equip(equipable); + EquipmentComponent.Equip(equipable); } public void Unequip(EquipableItem equipable) { - HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP); - VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT); + HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP); + VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT); - EquipmentComponent.Unequip(equipable); + EquipmentComponent.Unequip(equipable); } private static Vector3 GlobalInputVector { - get - { - var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown); - var input = new Vector3 - { - X = rawInput.X, - Z = rawInput.Y - }; - return input with { Y = 0f }; - } + get + { + var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown); + var input = new Vector3 + { + X = rawInput.X, + Z = rawInput.Y + }; + return input with { Y = 0f }; + } } private static float LeftStrafeInputVector => Input.GetActionStrength(GameInputs.StrafeLeft); @@ -296,143 +296,143 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide private void Attack() { - if (PlayerIsHittingGeometry()) - AnimationPlayer.Play("hit_wall"); - else if (!AnimationPlayer.IsPlaying()) - PlayAttackAnimation(); + if (PlayerIsHittingGeometry()) + AnimationPlayer.Play("hit_wall"); + else if (!AnimationPlayer.IsPlaying()) + PlayAttackAnimation(); } private void ThrowItem() { - var itemScene = GD.Load("res://src/items/throwable/ThrowableItem.tscn"); - var throwItem = itemScene.Instantiate(); - GetTree().Root.AddChildEx(throwItem); - throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0); - throwItem.GlobalRotation = GlobalRotation; + var itemScene = GD.Load("res://src/items/throwable/ThrowableItem.tscn"); + var throwItem = itemScene.Instantiate(); + GetTree().Root.AddChildEx(throwItem); + throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0); + throwItem.GlobalRotation = GlobalRotation; } private void PlayAttackAnimation() { - SfxDatabase.Instance.Play(((Weapon)EquipmentComponent.EquippedWeapon.Value).SoundEffect); - var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed; - AnimationPlayer.SetSpeedScale((float)attackSpeed); - AnimationPlayer.Play("attack"); + SfxDatabase.Instance.Play(((Weapon)EquipmentComponent.EquippedWeapon.Value).SoundEffect); + var attackSpeed = ((Weapon)EquipmentComponent.EquippedWeapon.Value).AttackSpeed; + AnimationPlayer.SetSpeedScale((float)attackSpeed); + AnimationPlayer.Play("attack"); } private void OnExitTree() { - PlayerLogic.Stop(); - PlayerBinding.Dispose(); - Hitbox.AreaEntered -= Hitbox_AreaEntered; - CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered; - HealthComponent.HealthReachedZero -= Die; - HealthTimer.Timeout -= OnHealthTimerTimeout; + PlayerLogic.Stop(); + PlayerBinding.Dispose(); + Hitbox.AreaEntered -= Hitbox_AreaEntered; + CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered; + HealthComponent.HealthReachedZero -= Die; + HealthTimer.Timeout -= OnHealthTimerTimeout; } private void Move(float delta) { - var rawInput = GlobalInputVector; - var strafeLeftInput = LeftStrafeInputVector; - var strafeRightInput = RightStrafeInputVector; + var rawInput = GlobalInputVector; + var strafeLeftInput = LeftStrafeInputVector; + var strafeRightInput = RightStrafeInputVector; - var transform = Transform; - transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis; - var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized(); - var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration; - _knockbackStrength *= 0.9f; - Transform = Transform with { Basis = transform.Basis }; - Velocity = velocity + (_knockbackDirection * _knockbackStrength); - if (!WalkSFX.Playing && !Velocity.IsZeroApprox()) - WalkSFX.Play(); - else if (Velocity.IsZeroApprox()) - WalkSFX.Stop(); - MoveAndSlide(); + var transform = Transform; + transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis; + var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized(); + var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration; + _knockbackStrength *= 0.9f; + Transform = Transform with { Basis = transform.Basis }; + Velocity = velocity + (_knockbackDirection * _knockbackStrength); + if (!WalkSFX.Playing && !Velocity.IsZeroApprox()) + WalkSFX.Play(); + else if (Velocity.IsZeroApprox()) + WalkSFX.Stop(); + MoveAndSlide(); } private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition; private void OnHealthTimerTimeout() { - if (VTComponent.CurrentVT.Value > 0) - { - if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption) - reduceOnTick = !reduceOnTick; + if (VTComponent.CurrentVT.Value > 0) + { + if (((Accessory)EquipmentComponent.EquippedAccessory.Value).AccessoryTag == AccessoryTag.HalfVTConsumption) + reduceOnTick = !reduceOnTick; - HealthComponent.Heal(1); + HealthComponent.Heal(1); - if (reduceOnTick) - VTComponent.Reduce(1); - } - else - HealthComponent.Damage(1); + if (reduceOnTick) + VTComponent.Reduce(1); + } + else + HealthComponent.Damage(1); } private void Hitbox_AreaEntered(Area3D area) { - var target = area.GetOwner(); - if (target is IEnemy enemy) - HitEnemy(enemy); + var target = area.GetOwner(); + if (target is IEnemy enemy) + HitEnemy(enemy); } private void HitEnemy(IEnemy enemy) { - var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity; - var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense; - var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck); - var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack; - var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement; + var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity; + var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense; + var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck); + var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack; + var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement; - if (isCriticalHit) - { - totalDamage += (int)(totalDamage * 0.5f); - SfxDatabase.Instance.Play(SoundEffect.Crit); - } + if (isCriticalHit) + { + totalDamage += (int)(totalDamage * 0.5f); + SfxDatabase.Instance.Play(SoundEffect.Crit); + } - var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance); - var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None); - enemy.HealthComponent.Damage(damageDealt); + var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance); + var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None); + enemy.HealthComponent.Damage(damageDealt); - if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable) - knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized()); - if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage) - HealthComponent.Damage(5); + if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable) + knockbackable.Knockback(0.3f, -CurrentBasis.Z.Normalized()); + if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.SelfDamage) + HealthComponent.Damage(5); } private void CollisionDetector_AreaEntered(Area3D area) { - if (area.GetParent() is InventoryItem inventoryItem) - { - var isAdded = Inventory.PickUpItem(inventoryItem); - if (isAdded) - inventoryItem.QueueFree(); - } - if (area.GetParent() is DroppedItem droppedItem) - { - var isAdded = Inventory.PickUpItem(droppedItem.Item); - if (isAdded) - droppedItem.QueueFree(); - } - if (area.GetParent() is ThrownItem thrownItem) - { - var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown); - if (isAdded) - thrownItem.QueueFree(); - } - if (area.GetParent() is Restorative restorative) - { - restorative.QueueFree(); - } + if (area.GetParent() is InventoryItem inventoryItem) + { + var isAdded = Inventory.PickUpItem(inventoryItem); + if (isAdded) + inventoryItem.QueueFree(); + } + if (area.GetParent() is DroppedItem droppedItem) + { + var isAdded = Inventory.PickUpItem(droppedItem.Item); + if (isAdded) + droppedItem.QueueFree(); + } + if (area.GetParent() is ThrownItem thrownItem) + { + var isAdded = Inventory.PickUpItem(thrownItem.ItemThatIsThrown); + if (isAdded) + thrownItem.QueueFree(); + } + if (area.GetParent() is Restorative restorative) + { + restorative.QueueFree(); + } } private bool PlayerIsHittingGeometry() { - var collisions = WallCheck.GetCollidingBodies(); - return collisions.Count > 0; + var collisions = WallCheck.GetCollidingBodies(); + return collisions.Count > 0; } private void WallCheck_BodyEntered(Node body) { - GD.Print("Hit wall"); - AnimationPlayer.Stop(); + GD.Print("Hit wall"); + AnimationPlayer.Stop(); } } diff --git a/Zennysoft.Game.Ma/src/ui/gallery/GalleryMenu.cs b/Zennysoft.Game.Ma/src/ui/gallery/GalleryMenu.cs index 6aefc341..86ba22fa 100644 --- a/Zennysoft.Game.Ma/src/ui/gallery/GalleryMenu.cs +++ b/Zennysoft.Game.Ma/src/ui/gallery/GalleryMenu.cs @@ -56,8 +56,17 @@ public partial class GalleryMenu : Control public void OnReady() { - GalleryData = new GalleryData() { PlaceholderImage1 = true }; - BackButton.Pressed += BackButton_Pressed; + GalleryData = new GalleryData() { PlaceholderImage1 = true }; + BackButton.Pressed += BackButton_Pressed; + } + + public override void _Input(InputEvent @event) + { + if (!Visible) + return; + + if (@event.IsActionPressed(GameInputs.Interact)) + BackButton.GrabFocus(); } private void BackButton_Pressed() => EmitSignal(SignalName.GalleryExited); diff --git a/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs b/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs index 893e660d..c6b71bc6 100644 --- a/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs +++ b/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs @@ -57,13 +57,4 @@ public partial class InGameUI : Control, IInGameUI InventoryMenu.Hide(); InventoryMenu.SetProcessInput(false); } - - public override void _UnhandledInput(InputEvent @event) - { - if (@event.IsActionPressed(GameInputs.Inventory) && !InventoryMenu.Visible) - { - GD.Print("Inventory button pressed"); - InGameUILogic.Input(new InGameUILogic.Input.ShowInventory()); - } - } } diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs index f45ed742..0371d8ba 100644 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs +++ b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs @@ -100,7 +100,7 @@ public partial class InventoryMenu : Control, IInventoryMenu SfxDatabase.Instance.Play(SoundEffect.MoveUI); } - public override void _Input(InputEvent @event) + public override void _UnhandledInput(InputEvent @event) { if (!Visible) return; @@ -108,12 +108,6 @@ public partial class InventoryMenu : Control, IInventoryMenu if ((!Input.IsActionJustPressed(GameInputs.UiUp) && Input.IsActionPressed(GameInputs.UiUp)) || (!Input.IsActionJustPressed(GameInputs.UiDown) && Input.IsActionPressed(GameInputs.UiDown))) AcceptEvent(); - if (Input.IsActionJustPressed(GameInputs.Inventory) && !(UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus())) - { - SfxDatabase.Instance.Play(SoundEffect.CancelUI); - AcceptEvent(); - _gameRepo.CloseInventory(); - } if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseButton.HasFocus() || DropButton.HasFocus() || ThrowButton.HasFocus())) { SfxDatabase.Instance.Play(SoundEffect.CancelUI); @@ -153,6 +147,7 @@ public partial class InventoryMenu : Control, IInventoryMenu } else { + SfxDatabase.Instance.Play(SoundEffect.CancelUI); _enableMenuSound = false; } } diff --git a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.cs b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.cs index 72304807..5220072b 100644 --- a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.cs +++ b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.cs @@ -2,6 +2,7 @@ using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; +using System; namespace Zennysoft.Game.Ma; public interface IPauseMenu : IControl @@ -10,6 +11,8 @@ public interface IPauseMenu : IControl void FadeOut(); event PauseMenu.UnpauseButtonPressedEventHandler UnpauseButtonPressed; event PauseMenu.TransitionCompletedEventHandler TransitionCompleted; + + public event Action ExitGamePressed; } [Meta(typeof(IAutoNode))] @@ -24,14 +27,32 @@ public partial class PauseMenu : Control, IPauseMenu [Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!; + [Node] public Button ResumeButton { get; set; } = default!; + [Node] public Button ExitButton { get; set; } = default!; + + public event Action ExitGamePressed; + public void OnResolved() { AnimationPlayer.AnimationFinished += OnAnimationFinished; + ResumeButton.Pressed += ResumeButton_Pressed; + ExitButton.Pressed += ExitButton_Pressed; } - public void FadeIn() => AnimationPlayer.Play("fade_in"); + private void ExitButton_Pressed() => ExitGamePressed?.Invoke(); + private void ResumeButton_Pressed() => FadeOut(); + public void FadeIn() + { + ResumeButton.GrabFocus(); + AnimationPlayer.Play("fade_in"); + } - public void FadeOut() => AnimationPlayer.Play("fade_out"); + public void FadeOut() + { + ResumeButton.ReleaseFocus(); + ExitButton.ReleaseFocus(); + AnimationPlayer.Play("fade_out"); + } public override void _UnhandledInput(InputEvent @event) { @@ -41,5 +62,7 @@ public partial class PauseMenu : Control, IPauseMenu public void OnAnimationFinished(StringName name) { + if (name == "fade_out") + Hide(); } } diff --git a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.tscn b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.tscn index 9e4cc691..b990a26e 100644 --- a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.tscn +++ b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseMenu.tscn @@ -1,4 +1,9 @@ -[gd_scene load_steps=5 format=3 uid="uid://blbqgw3wosc1w"] +[gd_scene load_steps=9 format=3 uid="uid://blbqgw3wosc1w"] + +[ext_resource type="Script" uid="uid://cbal5oeaha4nx" path="res://src/ui/pause_menu/PauseMenu.cs" id="1_1mfd6"] +[ext_resource type="FontFile" uid="uid://beh6d5lo5ihq0" path="res://src/ui/fonts/georgiai.ttf" id="2_o1qdr"] +[ext_resource type="StyleBox" uid="uid://bxuy4tnftibfq" path="res://src/options/SelectedOptionsBox.tres" id="2_xhp56"] +[ext_resource type="StyleBox" uid="uid://bl15q835s4ene" path="res://src/options/UnselectedOptionsBox.tres" id="3_o1qdr"] [sub_resource type="Animation" id="Animation_f1eqn"] length = 0.001 @@ -62,6 +67,7 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 +script = ExtResource("1_1mfd6") [node name="AnimationPlayer" type="AnimationPlayer" parent="."] unique_name_in_owner = true @@ -77,3 +83,53 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 color = Color(0, 0, 0, 1) + +[node name="CenterContainer" type="CenterContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="ResumeButton" type="Button" parent="CenterContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_fonts/font = ExtResource("2_o1qdr") +theme_override_font_sizes/font_size = 38 +theme_override_styles/focus = ExtResource("2_xhp56") +theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr") +theme_override_styles/disabled = ExtResource("3_o1qdr") +theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr") +theme_override_styles/hover_pressed = ExtResource("3_o1qdr") +theme_override_styles/hover_mirrored = ExtResource("3_o1qdr") +theme_override_styles/hover = ExtResource("3_o1qdr") +theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr") +theme_override_styles/pressed = ExtResource("3_o1qdr") +theme_override_styles/normal_mirrored = ExtResource("3_o1qdr") +theme_override_styles/normal = ExtResource("3_o1qdr") +text = "Resume" +flat = true + +[node name="ExitButton" type="Button" parent="CenterContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_fonts/font = ExtResource("2_o1qdr") +theme_override_font_sizes/font_size = 38 +theme_override_styles/focus = ExtResource("2_xhp56") +theme_override_styles/disabled_mirrored = ExtResource("3_o1qdr") +theme_override_styles/disabled = ExtResource("3_o1qdr") +theme_override_styles/hover_pressed_mirrored = ExtResource("3_o1qdr") +theme_override_styles/hover_pressed = ExtResource("3_o1qdr") +theme_override_styles/hover_mirrored = ExtResource("3_o1qdr") +theme_override_styles/hover = ExtResource("3_o1qdr") +theme_override_styles/pressed_mirrored = ExtResource("3_o1qdr") +theme_override_styles/pressed = ExtResource("3_o1qdr") +theme_override_styles/normal_mirrored = ExtResource("3_o1qdr") +theme_override_styles/normal = ExtResource("3_o1qdr") +text = "Exit Game" +flat = true