diff --git a/Zennysoft.Game.Ma.Implementation/Components/IEquipmentComponent.cs b/Zennysoft.Game.Ma.Implementation/Components/IEquipmentComponent.cs index 9cf42ca32..50532db4a 100644 --- a/Zennysoft.Game.Ma.Implementation/Components/IEquipmentComponent.cs +++ b/Zennysoft.Game.Ma.Implementation/Components/IEquipmentComponent.cs @@ -17,6 +17,8 @@ public interface IEquipmentComponent : IEntityComponent public bool IsItemEquipped(InventoryItem item); + public void UpdateEquipment(EquipableItem equipable); + public int BonusAttack { get; } public int BonusDefense { get; } diff --git a/Zennysoft.Game.Ma.Implementation/Equipment/Tags/WeaponTag.cs b/Zennysoft.Game.Ma.Implementation/Equipment/Tags/WeaponTag.cs index d52b17fba..46882f704 100644 --- a/Zennysoft.Game.Ma.Implementation/Equipment/Tags/WeaponTag.cs +++ b/Zennysoft.Game.Ma.Implementation/Equipment/Tags/WeaponTag.cs @@ -9,5 +9,6 @@ public enum WeaponTag Knockback, InverseHPAttackPower, RustChanceSelfAndEnemy, - Instakill + Instakill, + DegradeOnSwing } diff --git a/Zennysoft.Game.Ma/src/Components/EquipmentComponent.cs b/Zennysoft.Game.Ma/src/Components/EquipmentComponent.cs index cbf1bec62..757a0eb71 100644 --- a/Zennysoft.Game.Ma/src/Components/EquipmentComponent.cs +++ b/Zennysoft.Game.Ma/src/Components/EquipmentComponent.cs @@ -76,4 +76,6 @@ public class EquipmentComponent : IEquipmentComponent return item == _equippedWeapon.Value || item == _equippedArmor.Value || item == _equippedAccessory.Value; } + + public void UpdateEquipment(EquipableItem equipable) => EquipmentChanged?.Invoke(equipable); } diff --git a/Zennysoft.Game.Ma/src/app/App.cs b/Zennysoft.Game.Ma/src/app/App.cs index 425090c0e..75afe463e 100644 --- a/Zennysoft.Game.Ma/src/app/App.cs +++ b/Zennysoft.Game.Ma/src/app/App.cs @@ -261,6 +261,13 @@ public partial class App : Node, IApp MainMenu.StartGame -= OnStartGame; MainMenu.EnemyViewer -= OnEnemyViewer; + MainMenu.Gallery -= OnGallery; + MainMenu.Options -= OnOptions; MainMenu.Quit -= OnQuit; + + GalleryMenu.GalleryExited -= GalleryExited; + + OptionsMenu.OptionsMenuExited -= OptionsMenu_OptionsMenuExited; + OptionsMenu.DeleteSaveData -= DeleteSaveData; } } diff --git a/Zennysoft.Game.Ma/src/data_viewer/DataViewer.cs b/Zennysoft.Game.Ma/src/data_viewer/DataViewer.cs index 1d95f3ccd..fd1ae7eeb 100644 --- a/Zennysoft.Game.Ma/src/data_viewer/DataViewer.cs +++ b/Zennysoft.Game.Ma/src/data_viewer/DataViewer.cs @@ -54,111 +54,118 @@ public partial class DataViewer : Control, IDataViewer public void OnReady() { - BackButton.Pressed += BackButton_Pressed; - _enemies = [.. ModelPivot.GetChildren().Cast()]; - _currentModel = _enemies.First(); - DisplayEnemy(); + BackButton.Pressed += BackButton_Pressed; + _enemies = [.. ModelPivot.GetChildren().Cast()]; + _currentModel = _enemies.First(); + DisplayEnemy(); } - public void OnEnterTree() => GetTree().Paused = false; + public void OnEnterTree() + { + GetTree().Paused = false; + } - public void OnExitTree() => GetTree().Paused = false; + public void OnExitTree() + { + GetTree().Paused = false; + BackButton.Pressed -= BackButton_Pressed; + } private void BackButton_Pressed() => AppRepo.OnDataViewerExited(); public override void _Input(InputEvent @event) { - if (BackButton.HasFocus() && @event.IsActionPressed(GameInputs.Interact)) - { - GetTree().Paused = false; - BackButton.ReleaseFocus(); - return; - } + if (BackButton.HasFocus() && @event.IsActionPressed(GameInputs.Interact)) + { + GetTree().Paused = false; + BackButton.ReleaseFocus(); + return; + } - if (_currentModel == null || BackButton.HasFocus()) - return; + if (_currentModel == null || BackButton.HasFocus()) + return; - if (@event.IsActionPressed(GameInputs.Attack)) - _currentModel.PlayPrimaryAttackAnimation(); - if (@event.IsActionPressed(GameInputs.InventorySort)) - _currentModel.PlaySecondaryAttackAnimation(); - if (Input.IsActionJustPressed(GameInputs.Inventory)) - _currentModel.PlayActivateAnimation(); - if (@event.IsActionPressed(GameInputs.EnemyViewerWalk)) - _currentModel.PlayWalkAnimation(); - if (@event.IsActionReleased(GameInputs.EnemyViewerWalk)) - _currentModel.PlayIdleAnimation(); + if (@event.IsActionPressed(GameInputs.Attack)) + _currentModel.PlayPrimaryAttackAnimation(); + if (@event.IsActionPressed(GameInputs.InventorySort)) + _currentModel.PlaySecondaryAttackAnimation(); + if (Input.IsActionJustPressed(GameInputs.Inventory)) + _currentModel.PlayActivateAnimation(); + if (@event.IsActionPressed(GameInputs.EnemyViewerWalk)) + _currentModel.PlayWalkAnimation(); + if (@event.IsActionReleased(GameInputs.EnemyViewerWalk)) + _currentModel.PlayIdleAnimation(); - if (@event.IsActionPressed(GameInputs.Interact)) - { - GetTree().Paused = true; - BackButton.GrabFocus(); - } + if (@event.IsActionPressed(GameInputs.Interact)) + { + GetTree().Paused = true; + BackButton.GrabFocus(); + } - if (@event.IsActionPressed(GameInputs.StrafeRight)) - { - // Load next model - _enemies[_currentIndex].Hide(); - if (_currentIndex == _enemies.Count - 1) - _currentIndex = 0; - else - _currentIndex++; - DisplayEnemy(); - } - if (@event.IsActionPressed(GameInputs.StrafeLeft)) - { - _enemies[_currentIndex].Hide(); - // Load previous model - if (_currentIndex == 0) - _currentIndex = _enemies.Count - 1; - else - _currentIndex--; - DisplayEnemy(); - } + if (@event.IsActionPressed(GameInputs.StrafeRight)) + { + // Load next model + _enemies[_currentIndex].Hide(); + if (_currentIndex == _enemies.Count - 1) + _currentIndex = 0; + else + _currentIndex++; + DisplayEnemy(); + } + if (@event.IsActionPressed(GameInputs.StrafeLeft)) + { + _enemies[_currentIndex].Hide(); + // Load previous model + if (_currentIndex == 0) + _currentIndex = _enemies.Count - 1; + else + _currentIndex--; + DisplayEnemy(); + } } public override void _Process(double delta) { - if (_currentModel == null || BackButton.HasFocus()) - return; + if (_currentModel == null || BackButton.HasFocus()) + return; - var forwardStrength = Input.GetActionStrength(GameInputs.CameraForward); - Camera3D.Position = Camera3D.Position.MoveToward(CameraPivot.Position, _cameraSpeed * forwardStrength * (_cameraStartingPoint / 10)); - var backStrength = Input.GetActionStrength(GameInputs.CameraBack); - Camera3D.Position = Camera3D.Position.MoveToward(CameraPivot.Position, -_cameraSpeed * backStrength * (_cameraStartingPoint / 10)); - var leftStrength = Input.GetActionStrength(GameInputs.MoveLeft); - CameraPivot.RotateY(_cameraSpeed * leftStrength); - var rightStrength = Input.GetActionStrength(GameInputs.MoveRight); - CameraPivot.RotateY(-_cameraSpeed * rightStrength); + var forwardStrength = Input.GetActionStrength(GameInputs.CameraForward); + Camera3D.Position = Camera3D.Position.MoveToward(CameraPivot.Position, _cameraSpeed * forwardStrength * (_cameraStartingPoint / 10)); + var backStrength = Input.GetActionStrength(GameInputs.CameraBack); + Camera3D.Position = Camera3D.Position.MoveToward(CameraPivot.Position, -_cameraSpeed * backStrength * (_cameraStartingPoint / 10)); + var leftStrength = Input.GetActionStrength(GameInputs.MoveLeft); + CameraPivot.RotateY(_cameraSpeed * leftStrength); + var rightStrength = Input.GetActionStrength(GameInputs.MoveRight); + CameraPivot.RotateY(-_cameraSpeed * rightStrength); - Camera3D.Position = Camera3D.Position.Clamp(new Vector3(0, 0, _cameraStartingPoint / 2), new Vector3(0, 0, _cameraStartingPoint)); - ModelPivot.Rotation = ModelPivot.Rotation.Clamp(Mathf.DegToRad(-60), Mathf.DegToRad(60)); + Camera3D.Position = Camera3D.Position.Clamp(new Vector3(0, 0, _cameraStartingPoint / 2), new Vector3(0, 0, _cameraStartingPoint)); + ModelPivot.Rotation = ModelPivot.Rotation.Clamp(Mathf.DegToRad(-60), Mathf.DegToRad(60)); - if (_currentModel is EnemyModelView2D enemyModelView2D) - enemyModelView2D.SetCurrentDirection(_currentModel.GlobalBasis, -CameraPivot.Basis.Z); + if (_currentModel is EnemyModelView2D enemyModelView2D) + enemyModelView2D.SetCurrentDirection(_currentModel.GlobalBasis, -CameraPivot.Basis.Z); } private void DisplayEnemy() { - _currentModel = _enemies[_currentIndex]; + _currentModel = _enemies[_currentIndex]; - var size = _currentModel.GetSize(); - if (_currentModel is EnemyModelView2D) - _cameraStartingPoint = size.X / 50; - else - _cameraStartingPoint = size.X * 2; + var size = _currentModel.GetSize(); + if (_currentModel is EnemyModelView2D) + _cameraStartingPoint = size.X / 50; + else + _cameraStartingPoint = size.X * 2; - Camera3D.Position = new Vector3(Camera3D.Position.X, Camera3D.Position.Y, _cameraStartingPoint); - EnemyName.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Name : "Placeholder Text"; - Description.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Description : "Placeholder Text"; - HPValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.MaximumHP : "Placeholder Text"; - ATKValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.ATK : "Placeholder Text"; - DEFValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.DEF : "Placeholder Text"; - Drop1Value.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Drop1 : "Placeholder Text"; - Drop2Value.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Drop2 : "Placeholder Text"; - AffinityValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Affinity : "Placeholder Text"; - WeaknessValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Weakness : "Placeholder Text"; + Camera3D.Position = new Vector3(Camera3D.Position.X, Camera3D.Position.Y, _cameraStartingPoint); + EnemyName.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Name : "Placeholder Text"; + Description.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Description : "Placeholder Text"; + HPValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.MaximumHP : "Placeholder Text"; + ATKValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.ATK : "Placeholder Text"; + DEFValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.DEF : "Placeholder Text"; + Drop1Value.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Drop1 : "Placeholder Text"; + Drop2Value.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Drop2 : "Placeholder Text"; + AffinityValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Affinity : "Placeholder Text"; + WeaknessValue.Text = _currentModel.EnemyLoreInfo != null ? _currentModel.EnemyLoreInfo.Weakness : "Placeholder Text"; - _enemies[_currentIndex].Show(); + _enemies[_currentIndex].Show(); } } diff --git a/Zennysoft.Game.Ma/src/enemy/BossAModelView.cs b/Zennysoft.Game.Ma/src/enemy/BossAModelView.cs index 6f9daf5a2..4db571410 100644 --- a/Zennysoft.Game.Ma/src/enemy/BossAModelView.cs +++ b/Zennysoft.Game.Ma/src/enemy/BossAModelView.cs @@ -39,4 +39,10 @@ public partial class BossAModelView : EnemyModelView3D, INode3D ExplodingModel.Show(); DeathAnimation.Play("Animation"); } + + public void OnExitTree() + { + Hitbox.AreaEntered -= Hitbox_AreaEntered; + DeathAnimation.AnimationFinished -= DeathAnimation_AnimationFinished; + } } diff --git a/Zennysoft.Game.Ma/src/enemy/BossTypeA.cs b/Zennysoft.Game.Ma/src/enemy/BossTypeA.cs index 2d38bdd02..dcc24f0fe 100644 --- a/Zennysoft.Game.Ma/src/enemy/BossTypeA.cs +++ b/Zennysoft.Game.Ma/src/enemy/BossTypeA.cs @@ -180,5 +180,6 @@ public partial class BossTypeA : Enemy, IHaveEngagePlayerBehavior, IHaveFollowBe EngagePlayerBehavior.TakeAction -= PerformAction; PlayerDetector.BodyEntered -= PlayerDetector_BodyEntered; PlayerDetector.BodyExited -= PlayerDetector_BodyExited; + (EnemyModelView as BossAModelView).OnDeathAnimationCompleted -= EnemyModelView3D_OnDeathAnimationCompleted; } } diff --git a/Zennysoft.Game.Ma/src/enemy/Enemy2D.cs b/Zennysoft.Game.Ma/src/enemy/Enemy2D.cs index f98808513..72a23457c 100644 --- a/Zennysoft.Game.Ma/src/enemy/Enemy2D.cs +++ b/Zennysoft.Game.Ma/src/enemy/Enemy2D.cs @@ -69,4 +69,10 @@ public abstract partial class Enemy2D : Enemy if (body is IPlayer) _enemyLogic.Input(new EnemyLogic.Input.Alert()); } + + public new void OnExitTree() + { + base.OnExitTree(); + LineOfSight.BodyEntered -= LineOfSight_BodyEntered; + } } diff --git a/Zennysoft.Game.Ma/src/enemy/EnemyModelView.cs b/Zennysoft.Game.Ma/src/enemy/EnemyModelView.cs index 37d58e567..63b5ec0c4 100644 --- a/Zennysoft.Game.Ma/src/enemy/EnemyModelView.cs +++ b/Zennysoft.Game.Ma/src/enemy/EnemyModelView.cs @@ -129,5 +129,6 @@ public abstract partial class EnemyModelView : Node3D, IEnemyModelView { if (AnimationTree != null) AnimationTree.Get(_parametersPlayback).As().Stop(); + AnimationTree.AnimationFinished -= AnimationTree_AnimationFinished; } } diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/02. michael/Michael.cs b/Zennysoft.Game.Ma/src/enemy/enemy_types/02. michael/Michael.cs index 8fb35e240..2027457df 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/02. michael/Michael.cs +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/02. michael/Michael.cs @@ -18,23 +18,33 @@ public partial class Michael : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerBe public void OnReady() { - FollowBehavior.Init(NavigationAgent); - PatrolBehavior.Init(NavigationAgent); - PatrolBehavior.HomePosition = GlobalPosition; - PatrolBehavior.OnVelocityComputed += OnVelocityComputed; - FollowBehavior.OnVelocityComputed += OnVelocityComputed; - EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; - EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; - PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; - PlayerDetector.BodyExited += PlayerDetector_BodyExited; - SetPhysicsProcess(true); + FollowBehavior.Init(NavigationAgent); + PatrolBehavior.Init(NavigationAgent); + PatrolBehavior.HomePosition = GlobalPosition; + PatrolBehavior.OnVelocityComputed += OnVelocityComputed; + FollowBehavior.OnVelocityComputed += OnVelocityComputed; + EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction; + EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget; + PlayerDetector.BodyEntered += PlayerDetector_BodyEntered; + PlayerDetector.BodyExited += PlayerDetector_BodyExited; + SetPhysicsProcess(true); } public void OnResolved() { - _enemyLogic.Input(new EnemyLogic.Input.Patrol()); + _enemyLogic.Input(new EnemyLogic.Input.Patrol()); } - public override void Move() => EnemyModelView.PlayIdleAnimation(); + + public new void OnExitTree() + { + base.OnExitTree(); + PatrolBehavior.OnVelocityComputed -= OnVelocityComputed; + FollowBehavior.OnVelocityComputed -= OnVelocityComputed; + EngagePlayerBehavior.TakeAction -= EngagePlayerBehavior_TakeAction; + EngagePlayerBehavior.AcquireTarget -= EngagePlayerBehavior_AcquireTarget; + PlayerDetector.BodyEntered -= PlayerDetector_BodyEntered; + PlayerDetector.BodyExited -= PlayerDetector_BodyExited; + } } diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs index 715b9d569..5814c1783 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/13. gold sproingy/GoldSproingy.cs @@ -39,4 +39,12 @@ public partial class GoldSproingy : Enemy2D, IHavePatrolBehavior, IHaveFleeBehav } public override void Move() => EnemyModelView.PlayIdleAnimation(); + + public override void _ExitTree() + { + PatrolBehavior.OnVelocityComputed -= OnVelocityComputed; + PlayerDetector.BodyExited -= PlayerDetector_BodyExited; + FleeBehavior.OnVelocityComputed -= OnVelocityComputed; + PlayerDetector.BodyEntered -= GoldSproingyFlee; + } } \ No newline at end of file diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWall.cs b/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWall.cs index 7f4d15587..79b215a50 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWall.cs +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWall.cs @@ -52,4 +52,9 @@ public partial class DemonWall : Enemy3D { EnemyModelView.Attack(_maximumWallMoveAmount); } + + public void OnExitTree() + { + _attackTimer.Timeout -= AttackTimer_Timeout; + } } diff --git a/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWallArm.cs b/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWallArm.cs index fc7524b0f..3791cc000 100644 --- a/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWallArm.cs +++ b/Zennysoft.Game.Ma/src/enemy/enemy_types/16. demon wall/DemonWallArm.cs @@ -25,14 +25,19 @@ public partial class DemonWallArm : EnemyModelView public new void OnReady() { - Hitbox.AreaEntered += Hitbox_AreaEntered; - base.OnReady(); + Hitbox.AreaEntered += Hitbox_AreaEntered; + base.OnReady(); } private void Hitbox_AreaEntered(Area3D area) { - var target = area.GetOwner(); - if (target is IPlayer player) - base.OnPlayerHit(new AttackEventArgs(AttackData)); + var target = area.GetOwner(); + if (target is IPlayer player) + base.OnPlayerHit(new AttackEventArgs(AttackData)); + } + + public void OnExitTree() + { + Hitbox.AreaEntered -= Hitbox_AreaEntered; } } diff --git a/Zennysoft.Game.Ma/src/game/Game.cs b/Zennysoft.Game.Ma/src/game/Game.cs index e3d717211..0fdd4152a 100644 --- a/Zennysoft.Game.Ma/src/game/Game.cs +++ b/Zennysoft.Game.Ma/src/game/Game.cs @@ -608,13 +608,21 @@ public partial class Game : Node3D, IGame LoadNextLevel.Exit -= FloorClearMenu_Exit; LoadNextLevel.TransitionCompleted -= FloorClearMenu_TransitionCompleted; - _player.Inventory.BroadcastMessage -= BroadcastMessage; + OnLoadLevelRequest -= LoadLevel; GameRepo.RestorativePickedUp -= GameEventDepot_RestorativePickedUp; + GameRepo.CloseInventoryEvent -= ExitInventoryAction; + _player.Inventory.BroadcastMessage -= BroadcastMessage; + + _map.FloorLoaded -= OnFloorLoadFinished; + + _player.PlayerDied -= GameOver; GameOverMenu.NewGame -= OnNewGame; GameOverMenu.QuitGame -= OnQuit; + PauseMenu.ExitGamePressed -= OnQuit; + GameRepo.IsPaused.Sync -= IsPaused_Sync; } } diff --git a/Zennysoft.Game.Ma/src/item_rescue/ItemRescue.cs b/Zennysoft.Game.Ma/src/item_rescue/ItemRescue.cs index a0a5133cc..e04dff986 100644 --- a/Zennysoft.Game.Ma/src/item_rescue/ItemRescue.cs +++ b/Zennysoft.Game.Ma/src/item_rescue/ItemRescue.cs @@ -25,4 +25,9 @@ public partial class ItemRescue : Area3D BodyEntered -= OnItemRescueEntered; } + + public void OnExitTree() + { + BodyEntered -= OnItemRescueEntered; + } } diff --git a/Zennysoft.Game.Ma/src/items/misc/SetItem.cs b/Zennysoft.Game.Ma/src/items/misc/SetItem.cs index 7e40da394..6bf0c5687 100644 --- a/Zennysoft.Game.Ma/src/items/misc/SetItem.cs +++ b/Zennysoft.Game.Ma/src/items/misc/SetItem.cs @@ -54,4 +54,10 @@ public partial class SetItem : RigidBody3D { _stateMachine.Travel("timer"); } + + public void OnExitTree() + { + ExplosionArea.AreaEntered -= ExplosionArea_AreaEntered; + AnimationTree.AnimationFinished -= AnimationTree_AnimationFinished; + } } diff --git a/Zennysoft.Game.Ma/src/items/thrown/ThrownItem.cs b/Zennysoft.Game.Ma/src/items/thrown/ThrownItem.cs index c02d02f85..dc08a5b74 100644 --- a/Zennysoft.Game.Ma/src/items/thrown/ThrownItem.cs +++ b/Zennysoft.Game.Ma/src/items/thrown/ThrownItem.cs @@ -127,4 +127,10 @@ public partial class ThrownItem : RigidBody3D, IThrownItem enemy.HealthComponent.Damage(damageDealt); } } + + public void OnExitTree() + { + BodyEntered -= ThrownItem_BodyEntered; + Collision.AreaEntered -= Collision_AreaEntered; + } } \ No newline at end of file diff --git a/Zennysoft.Game.Ma/src/items/weapons/Weapon.cs b/Zennysoft.Game.Ma/src/items/weapons/Weapon.cs index 47df0bda2..7a24c0afe 100644 --- a/Zennysoft.Game.Ma/src/items/weapons/Weapon.cs +++ b/Zennysoft.Game.Ma/src/items/weapons/Weapon.cs @@ -20,6 +20,9 @@ public partial class Weapon : EquipableItem public void OnReady() { _sprite.Texture = Stats.Texture; + _bonusDamage = Stats.BonusAttack; + _bonusDefense = Stats.BonusDefense; + _bonusLuck = Stats.BonusLuck; } public override string ItemName => Stats.Name; @@ -51,11 +54,11 @@ public partial class Weapon : EquipableItem public void SetWeaponDefense(int newBonus) => _bonusDefense = newBonus; - public override int BonusAttack { get => Stats.BonusAttack + _bonusDamage; } + public override int BonusAttack { get => _bonusDamage; } - public override int BonusDefense { get => Stats.BonusDefense + _bonusDefense; } + public override int BonusDefense { get => _bonusDefense; } - public override int BonusLuck { get => Stats.BonusLuck + _bonusLuck; } + public override int BonusLuck { get => _bonusLuck; } [Save("weapon_bonus_damage")] private int _bonusDamage { get; set; } = 0; diff --git a/Zennysoft.Game.Ma/src/items/weapons/resources/ShiningHalberd.tres b/Zennysoft.Game.Ma/src/items/weapons/resources/ShiningHalberd.tres index cc3c6bd79..95288bee0 100644 --- a/Zennysoft.Game.Ma/src/items/weapons/resources/ShiningHalberd.tres +++ b/Zennysoft.Game.Ma/src/items/weapons/resources/ShiningHalberd.tres @@ -7,14 +7,15 @@ script = ExtResource("2_vrork") AttackSpeed = 0.75 WeaponElement = 0 -WeaponTag = 0 +WeaponTag = 8 +SelfDamage = 0 SoundEffect = 23 Name = "Shining Halberd" Description = "Weapon that gradually becomes weaker." SpawnRate = 0.3 BonusAttack = 8 BonusDefense = 0 -BonusLuck = 0.05 +BonusLuck = 5 BonusHP = 0 BonusVT = 0 AeolicResistance = 0 diff --git a/Zennysoft.Game.Ma/src/map/UnlockableDoor.cs b/Zennysoft.Game.Ma/src/map/UnlockableDoor.cs index a8b5a3228..0605031a5 100644 --- a/Zennysoft.Game.Ma/src/map/UnlockableDoor.cs +++ b/Zennysoft.Game.Ma/src/map/UnlockableDoor.cs @@ -11,13 +11,18 @@ public partial class UnlockableDoor : Node3D, IDoor public void OnReady() { - UnlockArea.AreaEntered += UnlockArea_AreaEntered; + UnlockArea.AreaEntered += UnlockArea_AreaEntered; } private void UnlockArea_AreaEntered(Area3D area) { - var children = GetChildren(); - foreach (var child in children) - child.QueueFree(); + var children = GetChildren(); + foreach (var child in children) + child.QueueFree(); + } + + public void OnExitTree() + { + UnlockArea.AreaEntered -= UnlockArea_AreaEntered; } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/Altar.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/Altar.cs index bc25dfd3e..2ca412e16 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/Altar.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/Altar.cs @@ -61,4 +61,10 @@ public partial class Altar : SpecialFloor, IDungeonFloor } public void ExitReached() => Game.FloorExitReached(); + + public void OnExitTree() + { + Exit.AreaEntered -= Exit_AreaEntered; + NoExitArea.AreaEntered -= NoExitArea_AreaEntered; + } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomA.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomA.cs index 136145ab6..cacefea03 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomA.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomA.cs @@ -72,4 +72,12 @@ public partial class BossRoomA : SpecialFloor, IBossRoom, IDungeonFloor } public override (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() { return (PlayerSpawn.Rotation, new Vector3(PlayerSpawn.GlobalPosition.X, -2.5f, PlayerSpawn.GlobalPosition.Z)); } + + public void OnExitTree() + { + ActivateTrap.BodyEntered -= ActivateTrap_BodyEntered; + _exit.AreaEntered -= Exit_AreaEntered; + OxFace.HealthComponent.HealthReachedZero -= CheckForBossFightEnd; + HorseHead.HealthComponent.HealthReachedZero -= CheckForBossFightEnd; + } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomB.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomB.cs index 3a1047fcf..1b76d7f28 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomB.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/BossRoomB.cs @@ -1,7 +1,6 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; -using System.Collections.Immutable; using Zennysoft.Ma.Adapter; namespace Zennysoft.Game.Ma; @@ -47,4 +46,10 @@ public partial class BossRoomB : SpecialFloor, IBossRoom, IDungeonFloor if (area.GetOwner() is IPlayer) ExitReached(); } + + public void OnExitTree() + { + ActivateTrap.BodyEntered -= ActivateTrap_AreaEntered; + _exit.AreaEntered -= Exit_AreaEntered; + } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/CorridorRoom.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/CorridorRoom.cs index 5117107cc..d5589720e 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/CorridorRoom.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/CorridorRoom.cs @@ -18,13 +18,18 @@ public partial class CorridorRoom : Node3D public void Setup() { - if (_room != null) - _room.BodyEntered += Room_BodyEntered; + if (_room != null) + _room.BodyEntered += Room_BodyEntered; } private void Room_BodyEntered(Node3D body) { - if (!Game.CurrentFloor.FloorIsLoaded) - return; + if (!Game.CurrentFloor.FloorIsLoaded) + return; + } + + public void OnExitTree() + { + _room.BodyEntered -= Room_BodyEntered; } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/ExitRoom.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/ExitRoom.cs index b3c0ce5be..6f8d33460 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/ExitRoom.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/ExitRoom.cs @@ -18,15 +18,21 @@ public partial class ExitRoom : DungeonRoom public override void _Ready() { - _exit.AreaEntered += Exit_AreaEntered; + _exit.AreaEntered += Exit_AreaEntered; } public void ExitReached() - => Game.FloorExitReached(); + => Game.FloorExitReached(); private void Exit_AreaEntered(Area3D area) { - if (area.GetOwner() is IPlayer) - ExitReached(); + if (area.GetOwner() is IPlayer) + ExitReached(); + } + + public new void OnExitTree() + { + base.OnExitTree(); + _exit.AreaEntered -= Exit_AreaEntered; } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/FinalFloor.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/FinalFloor.cs index 6e2a4e70d..8346a3a0c 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/FinalFloor.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/FinalFloor.cs @@ -3,6 +3,7 @@ using Chickensoft.Introspection; using Godot; using System.Linq; using Zennysoft.Ma.Adapter; +using static System.Net.Mime.MediaTypeNames; namespace Zennysoft.Game.Ma; @@ -24,4 +25,9 @@ public partial class FinalFloor : SpecialFloor { _player.Die(); } + + public void OnExitTree() + { + Exit.AreaEntered -= Exit_AreaEntered; + } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/JumpScareRoom.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/JumpScareRoom.cs index fc569b62c..3bad24bf2 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/JumpScareRoom.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/JumpScareRoom.cs @@ -28,4 +28,10 @@ public partial class JumpScareRoom : DungeonRoom DialogueController.ShowDialogue(Dialogue, "general"); JumpScare.SetMonitoring(false); } + + public new void OnExitTree() + { + base.OnExitTree(); + JumpScare.AreaEntered -= JumpScare_AreaEntered; + } } diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs index 89509df20..75cd5501b 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs @@ -85,4 +85,12 @@ public partial class Overworld : SpecialFloor, IDungeonFloor public override (Vector3 Rotation, Vector3 Position) GetPlayerSpawnPoint() { return (PlayerSpawnPoint.Rotation, new Vector3(PlayerSpawnPoint.GlobalPosition.X, 2.4f, PlayerSpawnPoint.GlobalPosition.Z)); } + public void OnExitTree() + { + Exit.AreaEntered -= Exit_AreaEntered; + RestoreArea.AreaEntered -= RestoreArea_AreaEntered; + RestoreArea.AreaExited -= RestoreArea_AreaExited; + RestoreTimer.Timeout -= RestoreTimer_Timeout; + } + } diff --git a/Zennysoft.Game.Ma/src/minimap/MapRevealerCube.cs b/Zennysoft.Game.Ma/src/minimap/MapRevealerCube.cs index 5d516a578..a5a07c6e8 100644 --- a/Zennysoft.Game.Ma/src/minimap/MapRevealerCube.cs +++ b/Zennysoft.Game.Ma/src/minimap/MapRevealerCube.cs @@ -18,4 +18,9 @@ public partial class MapRevealerCube : Node3D } private void Area3D_AreaEntered(Area3D area) => MeshInstance3D.Hide(); + + public void OnExitTree() + { + Area3D.AreaEntered -= Area3D_AreaEntered; + } } diff --git a/Zennysoft.Game.Ma/src/minimap/Minimap.cs b/Zennysoft.Game.Ma/src/minimap/Minimap.cs index 333352a8a..f55f76404 100644 --- a/Zennysoft.Game.Ma/src/minimap/Minimap.cs +++ b/Zennysoft.Game.Ma/src/minimap/Minimap.cs @@ -35,4 +35,9 @@ public partial class Minimap : Control { LayerNumberText.Text = $"{obj:D2}"; } + + public void OnExitTree() + { + _map.CurrentFloorNumber.Sync -= CurrentFloorNumber_Sync; + } } diff --git a/Zennysoft.Game.Ma/src/npc/Npc.cs b/Zennysoft.Game.Ma/src/npc/Npc.cs index 1afc5cdb2..fa0054fdc 100644 --- a/Zennysoft.Game.Ma/src/npc/Npc.cs +++ b/Zennysoft.Game.Ma/src/npc/Npc.cs @@ -71,14 +71,11 @@ public partial class Npc : Node3D } } - public partial class Gesthemii : Npc + public void OnExitTree() { - public override void _UnhandledInput(InputEvent @event) - { - if (@event.IsActionPressed(GameInputs.Interact) && _isInDialogueZone) - { - DialogueController.ShowDialogue(Dialogue, "general"); - } - } + DialogueZone.BodyEntered -= DialogueZone_BodyEntered; + DialogueZone.BodyExited -= DialogueZone_BodyExited; + DialogueExitZone.BodyExited -= DialogueExitZone_BodyExited; + Hitbox.AreaEntered -= Hitbox_AreaEntered; } } diff --git a/Zennysoft.Game.Ma/src/player/Player.cs b/Zennysoft.Game.Ma/src/player/Player.cs index 2e568a41e..59a6f60fd 100644 --- a/Zennysoft.Game.Ma/src/player/Player.cs +++ b/Zennysoft.Game.Ma/src/player/Player.cs @@ -323,6 +323,12 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide AnimationPlayer.Play("hit_wall"); else if (!AnimationPlayer.IsPlaying()) PlayAttackAnimation(); + else + return; + + var weapon = EquipmentComponent.EquippedWeapon.Value as Weapon; + if (weapon.WeaponTag == WeaponTag.DegradeOnSwing) + _playerEffectService.Degrade(); } private void ThrowItem() @@ -367,6 +373,10 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered; HealthComponent.HealthReachedZero -= Die; HealthTimer.Timeout -= OnHealthTimerTimeout; + HealthComponent.CurrentHP.Changed -= InverseHPToAttackPowerSync; + HealthComponent.HealthReachedZero -= Die; + ExperiencePointsComponent.PlayerLevelUp -= OnLevelUp; + PlayerFXAnimations.AnimationFinished -= PlayerFXAnimations_AnimationFinished; } private void Move(float delta) diff --git a/Zennysoft.Game.Ma/src/player/PlayerEffectService.cs b/Zennysoft.Game.Ma/src/player/PlayerEffectService.cs index 8e17a933b..dd655a295 100644 --- a/Zennysoft.Game.Ma/src/player/PlayerEffectService.cs +++ b/Zennysoft.Game.Ma/src/player/PlayerEffectService.cs @@ -1,4 +1,5 @@ using Godot; +using Zennysoft.Game.Ma; using Zennysoft.Ma.Adapter; using Zennysoft.Ma.Adapter.Entity; @@ -23,4 +24,12 @@ internal class PlayerEffectService if (rand <= _player.TotalLuck) enemy.Die(); } + + public void Degrade() + { + var weapon = _player.EquipmentComponent.EquippedWeapon.Value as Weapon; + var newAttack = Mathf.Max(weapon.BonusAttack - 1, 0); + weapon.SetWeaponAttack(newAttack); + _player.EquipmentComponent.UpdateEquipment(weapon); + } } \ No newline at end of file diff --git a/Zennysoft.Game.Ma/src/quest/QuestTest.cs b/Zennysoft.Game.Ma/src/quest/QuestTest.cs index fc1e60fcb..e6f5384c7 100644 --- a/Zennysoft.Game.Ma/src/quest/QuestTest.cs +++ b/Zennysoft.Game.Ma/src/quest/QuestTest.cs @@ -22,4 +22,9 @@ public partial class QuestTest : Area3D Game.QuestData.QuestMarker1 = true; QueueFree(); } + + public void OnExitTree() + { + AreaEntered -= QuestTest_AreaEntered; + } }