From 230b47061d4653de70387a39c586dfe0034dcad0 Mon Sep 17 00:00:00 2001 From: Zenny Date: Wed, 11 Feb 2026 15:25:20 -0800 Subject: [PATCH] Add item spawn menu Fix game over bug Start adding more implementation for jewels --- .../Calculators/IDamageCalculator.cs | 2 +- .../Components/IExperiencePointsComponent.cs | 2 + .../Equipment/Augment.cs | 9 + .../Equipment/EquipableItem.cs | 5 +- .../Equipment/Tags}/JewelTags.cs | 0 .../Game/GameRepo.cs | 4 +- .../gamestates/GameState.State.GameOver.cs | 9 +- .../Item/IAugmentItem.cs | 7 + .../Item/IInventory.cs | 2 + .../Player/IPlayer.cs | 2 + .../Components/ExperiencePointsComponent.cs | 1 + Zennysoft.Game.Ma/src/game/Game.cs | 2 + Zennysoft.Game.Ma/src/game/IGame.cs | 2 + Zennysoft.Game.Ma/src/items/Inventory.cs | 2 + .../src/items/dropped/DroppedItem.cs | 4 +- .../src/items/jewels/Augment.cs.uid | 1 + Zennysoft.Game.Ma/src/items/jewels/Jewel.cs | 40 +- .../items/jewels/resources/HydricJewel.tres | 3 +- .../items/jewels/resources/MeditativeOrb.tres | 1 + .../src/map/dungeon/code/Overworld.cs | 23 + .../floors/Special Floors/Overworld.tscn | 14 +- Zennysoft.Game.Ma/src/player/Player.cs | 43 +- .../src/ui/in_game_ui/InGameUI.cs | 2 + .../src/ui/in_game_ui/InGameUI.tscn | 8 +- .../src/ui/inventory_menu/InventoryMenu.cs | 333 -------------- .../ui/inventory_menu/InventoryMenu.cs.uid | 1 - .../src/ui/inventory_menu/InventoryMenu.tscn | 344 +++++++++++++- .../src/ui/inventory_menu/InventoryMenu2.cs | 68 ++- .../src/ui/inventory_menu/InventoryMenu2.tscn | 1 + .../src/ui/inventory_menu/ItemRescueMenu.cs | 203 ++++++++ .../ui/inventory_menu/ItemRescueMenu.cs.uid | 1 + .../src/ui/inventory_menu/ItemRescueMenu.tscn | 434 ++++++++++++++++++ 32 files changed, 1215 insertions(+), 358 deletions(-) create mode 100644 Zennysoft.Game.Ma.Implementation/Equipment/Augment.cs rename {Zennysoft.Game.Ma/src/items/jewels => Zennysoft.Game.Ma.Implementation/Equipment/Tags}/JewelTags.cs (100%) create mode 100644 Zennysoft.Game.Ma.Implementation/Item/IAugmentItem.cs create mode 100644 Zennysoft.Game.Ma/src/items/jewels/Augment.cs.uid delete mode 100644 Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs delete mode 100644 Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs.uid create mode 100644 Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.cs create mode 100644 Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.cs.uid create mode 100644 Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.tscn diff --git a/Zennysoft.Game.Ma.Implementation/Calculators/IDamageCalculator.cs b/Zennysoft.Game.Ma.Implementation/Calculators/IDamageCalculator.cs index da9bb9bf1..667154002 100644 --- a/Zennysoft.Game.Ma.Implementation/Calculators/IDamageCalculator.cs +++ b/Zennysoft.Game.Ma.Implementation/Calculators/IDamageCalculator.cs @@ -25,7 +25,7 @@ namespace Zennysoft.Ma.Adapter int incomingDamage, double elementalResistance) { - var result = incomingDamage - (int)(incomingDamage * elementalResistance); + var result = incomingDamage - (int)(incomingDamage * (elementalResistance / 100)); return result; } } diff --git a/Zennysoft.Game.Ma.Implementation/Components/IExperiencePointsComponent.cs b/Zennysoft.Game.Ma.Implementation/Components/IExperiencePointsComponent.cs index a08c7dbd8..09d9a2153 100644 --- a/Zennysoft.Game.Ma.Implementation/Components/IExperiencePointsComponent.cs +++ b/Zennysoft.Game.Ma.Implementation/Components/IExperiencePointsComponent.cs @@ -12,6 +12,8 @@ public interface IExperiencePointsComponent : IEntityComponent public IAutoProp Level { get; } + public void ModifyExpGainRate(double newRate); + public void Gain(int baseExpGain); public void LevelUp(); diff --git a/Zennysoft.Game.Ma.Implementation/Equipment/Augment.cs b/Zennysoft.Game.Ma.Implementation/Equipment/Augment.cs new file mode 100644 index 000000000..65f81c08a --- /dev/null +++ b/Zennysoft.Game.Ma.Implementation/Equipment/Augment.cs @@ -0,0 +1,9 @@ +public class Augment +{ + public JewelTags AugmentTag; + + public Augment(JewelTags tag) + { + AugmentTag = tag; + } +} diff --git a/Zennysoft.Game.Ma.Implementation/Equipment/EquipableItem.cs b/Zennysoft.Game.Ma.Implementation/Equipment/EquipableItem.cs index 423411ebe..ea8e19a4a 100644 --- a/Zennysoft.Game.Ma.Implementation/Equipment/EquipableItem.cs +++ b/Zennysoft.Game.Ma.Implementation/Equipment/EquipableItem.cs @@ -1,5 +1,4 @@ -using Chickensoft.Collections; -using Chickensoft.Introspection; +using Chickensoft.Introspection; using Chickensoft.Serialization; using Zennysoft.Ma.Adapter.Entity; @@ -22,6 +21,8 @@ public abstract partial class EquipableItem : InventoryItem [Save("equipment_is_glued")] public bool Glued { get; set; } + public virtual Augment? Augment { get; set; } + [Save("bonus_elemental_resist_stats")] public virtual ElementalResistanceSet ElementalResistance { get; } = new ElementalResistanceSet(0, 0, 0, 0, 0, 0, 0); } diff --git a/Zennysoft.Game.Ma/src/items/jewels/JewelTags.cs b/Zennysoft.Game.Ma.Implementation/Equipment/Tags/JewelTags.cs similarity index 100% rename from Zennysoft.Game.Ma/src/items/jewels/JewelTags.cs rename to Zennysoft.Game.Ma.Implementation/Equipment/Tags/JewelTags.cs diff --git a/Zennysoft.Game.Ma.Implementation/Game/GameRepo.cs b/Zennysoft.Game.Ma.Implementation/Game/GameRepo.cs index 7667fa4f0..a53f328c0 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/GameRepo.cs +++ b/Zennysoft.Game.Ma.Implementation/Game/GameRepo.cs @@ -110,14 +110,14 @@ public class GameRepo : IGameRepo { AnnounceMessageInInventory("Experience points temporarily doubled."); DoubleExpTimeStart?.Invoke(lengthOfEffect.Seconds); - ExpRate = 2; + ExpRate *= 2; } public void EndDoubleExp() { AnnounceMessageOnMainScreen("Experience points effect wore off."); DoubleExpTimeEnd?.Invoke(); - ExpRate = 1; + ExpRate /= 2; } public void AnnounceMessageOnMainScreen(string message) diff --git a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.GameOver.cs b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.GameOver.cs index 2ae83f958..aca31e6cc 100644 --- a/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.GameOver.cs +++ b/Zennysoft.Game.Ma.Implementation/Game/state/gamestates/GameState.State.GameOver.cs @@ -8,13 +8,20 @@ public partial class GameState public partial record State { [Meta, LogicBlock(typeof(State), Diagram = true)] - public partial record GameOver : State, IGet + public partial record GameOver : InGame, IGet, IGet { public Transition On(in Input.NewGame input) { Output(new Output.InitializeGame()); 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.Implementation/Item/IAugmentItem.cs b/Zennysoft.Game.Ma.Implementation/Item/IAugmentItem.cs new file mode 100644 index 000000000..e0455f330 --- /dev/null +++ b/Zennysoft.Game.Ma.Implementation/Item/IAugmentItem.cs @@ -0,0 +1,7 @@ +namespace Zennysoft.Ma.Adapter +{ + public interface IAugmentItem + { + public JewelTags Augment { get; } + } +} diff --git a/Zennysoft.Game.Ma.Implementation/Item/IInventory.cs b/Zennysoft.Game.Ma.Implementation/Item/IInventory.cs index 9e050a09a..01b6218fe 100644 --- a/Zennysoft.Game.Ma.Implementation/Item/IInventory.cs +++ b/Zennysoft.Game.Ma.Implementation/Item/IInventory.cs @@ -14,6 +14,8 @@ public interface IInventory public bool Sort(EquipableItem currentWeapon, EquipableItem currentArmor, EquipableItem currentAccessory, EquipableItem ammo); + public bool AtCapacity(); + public event Action BroadcastMessage; public event Action InventoryChanged; } diff --git a/Zennysoft.Game.Ma.Implementation/Player/IPlayer.cs b/Zennysoft.Game.Ma.Implementation/Player/IPlayer.cs index c1c69a243..1b8a695e6 100644 --- a/Zennysoft.Game.Ma.Implementation/Player/IPlayer.cs +++ b/Zennysoft.Game.Ma.Implementation/Player/IPlayer.cs @@ -26,6 +26,8 @@ public interface IPlayer : IKillable, ICharacterBody3D public void PlayJumpScareAnimation(); + //public void AugmentItem(IAugmentItem jewel, EquipableItem equipableItem); + public IInventory Inventory { get; } public IHealthComponent HealthComponent { get; } diff --git a/Zennysoft.Game.Ma/src/Components/ExperiencePointsComponent.cs b/Zennysoft.Game.Ma/src/Components/ExperiencePointsComponent.cs index bb0e14931..1fee4d89b 100644 --- a/Zennysoft.Game.Ma/src/Components/ExperiencePointsComponent.cs +++ b/Zennysoft.Game.Ma/src/Components/ExperiencePointsComponent.cs @@ -51,6 +51,7 @@ public class ExperiencePointsComponent : IExperiencePointsComponent var cappedAmount = Math.Min(baseExpGain + _currentExp.Value, _expToNextLevel.Value); _currentExp.OnNext(cappedAmount); } + public void ModifyExpGainRate(double newRate) => _expGainRate.OnNext(newRate); public void LevelUp() { diff --git a/Zennysoft.Game.Ma/src/game/Game.cs b/Zennysoft.Game.Ma/src/game/Game.cs index 75245e3ae..21e74e89f 100644 --- a/Zennysoft.Game.Ma/src/game/Game.cs +++ b/Zennysoft.Game.Ma/src/game/Game.cs @@ -69,6 +69,8 @@ public partial class Game : Node3D, IGame public QuestData QuestData { get; private set; } + public ItemRescueMenu ItemRescueMenu { get => InGameUI.ItemRescueMenu; } + private EffectService _effectService; private IInstantiator _instantiator; diff --git a/Zennysoft.Game.Ma/src/game/IGame.cs b/Zennysoft.Game.Ma/src/game/IGame.cs index 3287b7cc7..41d88e50b 100644 --- a/Zennysoft.Game.Ma/src/game/IGame.cs +++ b/Zennysoft.Game.Ma/src/game/IGame.cs @@ -32,6 +32,8 @@ public interface IGame : IProvide, IProvide, IProvide public Task Save(); + public ItemRescueMenu ItemRescueMenu { get; } + public QuestData QuestData { get; } public event Action GameExitRequested; diff --git a/Zennysoft.Game.Ma/src/items/Inventory.cs b/Zennysoft.Game.Ma/src/items/Inventory.cs index 279a86eee..52c1ecb95 100644 --- a/Zennysoft.Game.Ma/src/items/Inventory.cs +++ b/Zennysoft.Game.Ma/src/items/Inventory.cs @@ -54,6 +54,8 @@ public partial class Inventory : Node, IInventory return true; } + public bool AtCapacity() => Items.Count >= _maxInventorySize; + public bool TryInsert(InventoryItem inventoryItem, int index) { if (Items.Count >= _maxInventorySize || index >= _maxInventorySize || index < 0) diff --git a/Zennysoft.Game.Ma/src/items/dropped/DroppedItem.cs b/Zennysoft.Game.Ma/src/items/dropped/DroppedItem.cs index e3897bfe7..94a98e124 100644 --- a/Zennysoft.Game.Ma/src/items/dropped/DroppedItem.cs +++ b/Zennysoft.Game.Ma/src/items/dropped/DroppedItem.cs @@ -49,8 +49,8 @@ public partial class DroppedItem : RigidBody3D, IDroppedItem public void RescueItem() { ContactMonitor = false; - Pickup.Monitorable = false; - Pickup.Monitoring = false; + Pickup.SetDeferred(Area3D.PropertyName.Monitorable, false); + Pickup.SetDeferred(Area3D.PropertyName.Monitoring, false); SfxDatabase.Instance.Play(SoundEffect.Transfer); PlayRescueAnimation(); Game.RescuedItems.Items.Add(Item); diff --git a/Zennysoft.Game.Ma/src/items/jewels/Augment.cs.uid b/Zennysoft.Game.Ma/src/items/jewels/Augment.cs.uid new file mode 100644 index 000000000..9e870b6e5 --- /dev/null +++ b/Zennysoft.Game.Ma/src/items/jewels/Augment.cs.uid @@ -0,0 +1 @@ +uid://xlqkn5j388il diff --git a/Zennysoft.Game.Ma/src/items/jewels/Jewel.cs b/Zennysoft.Game.Ma/src/items/jewels/Jewel.cs index e87bac67a..5aedbd883 100644 --- a/Zennysoft.Game.Ma/src/items/jewels/Jewel.cs +++ b/Zennysoft.Game.Ma/src/items/jewels/Jewel.cs @@ -6,7 +6,7 @@ using Zennysoft.Game.Ma; using Zennysoft.Ma.Adapter; [Meta(typeof(IAutoNode)), Id("jewel")] -public partial class Jewel : InventoryItem +public partial class Jewel : InventoryItem, IAugmentItem { public override void _Notification(int what) => this.Notify(what); @@ -34,4 +34,42 @@ public partial class Jewel : InventoryItem [Export] [Save("jewel_stats")] public JewelStats Stats { get; set; } = new JewelStats(); + + public JewelTags Augment => Stats.JewelTag; + + public void ApplyAugment(Weapon weapon) + { + weapon.Augment = new Augment(Stats.JewelTag); + switch (Stats.JewelTag) + { + case JewelTags.AeolicElement: + weapon.Stats.WeaponElement = ElementType.Aeolic; + break; + } + } + + public void ApplyAugment(Armor armor) + { + armor.Augment = new Augment(Stats.JewelTag); + switch (Stats.JewelTag) + { + case JewelTags.AeolicElement: + armor.Stats.AeolicResistance += 25; + break; + case JewelTags.HydricElement: + armor.Stats.HydricResistance += 25; + break; + case JewelTags.IgneousElement: + armor.Stats.IgneousResistance += 25; + break; + case JewelTags.TelluricElement: + armor.Stats.TelluricResistance += 25; + break; + } + } + + public void ApplyAugment(Accessory accessory) + { + accessory.Augment = new Augment(Stats.JewelTag); + } } diff --git a/Zennysoft.Game.Ma/src/items/jewels/resources/HydricJewel.tres b/Zennysoft.Game.Ma/src/items/jewels/resources/HydricJewel.tres index d68f07873..e122a33a5 100644 --- a/Zennysoft.Game.Ma/src/items/jewels/resources/HydricJewel.tres +++ b/Zennysoft.Game.Ma/src/items/jewels/resources/HydricJewel.tres @@ -5,8 +5,9 @@ [resource] script = ExtResource("1_cyti8") +JewelTag = 7 Name = "Hydric Jewel" -Description = "Hydric e" +Description = "Add Hydric damage to Weapon or Hydric resistance to Armor." SpawnRate = 0.5 BonusAttack = 0 BonusDefense = 0 diff --git a/Zennysoft.Game.Ma/src/items/jewels/resources/MeditativeOrb.tres b/Zennysoft.Game.Ma/src/items/jewels/resources/MeditativeOrb.tres index f2907435d..673222434 100644 --- a/Zennysoft.Game.Ma/src/items/jewels/resources/MeditativeOrb.tres +++ b/Zennysoft.Game.Ma/src/items/jewels/resources/MeditativeOrb.tres @@ -5,6 +5,7 @@ [resource] script = ExtResource("1_6e2y5") +JewelTag = 9 Name = "Meditative Stone" Description = "" SpawnRate = 0.5 diff --git a/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs b/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs index 75cd5501b..569f32a52 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs +++ b/Zennysoft.Game.Ma/src/map/dungeon/code/Overworld.cs @@ -15,8 +15,12 @@ public partial class Overworld : SpecialFloor, IDungeonFloor [Dependency] protected IPlayer Player => this.DependOn(); + [Dependency] protected IGameRepo GameRepo => this.DependOn(); + [Node] public Marker3D PlayerSpawnPoint { get; set; } = default!; + [Node] public Area3D ItemRescueInteractZone { get; set; } = default!; + [Node] private Area3D Exit { get; set; } = default!; [Node] private Area3D RestoreArea { get; set; } = default!; @@ -25,6 +29,8 @@ public partial class Overworld : SpecialFloor, IDungeonFloor private Timer RestoreTimer { get; set; } + private bool _insideItemRescueZone = false; + public override void InitializeDungeon() { Show(); @@ -37,11 +43,28 @@ public partial class Overworld : SpecialFloor, IDungeonFloor AddChild(RestoreTimer); FloorIsLoaded = true; + ItemRescueInteractZone.AreaEntered += ItemRescueInteractZone_AreaEntered; var dimmableAudio = DimmableAudio.GetChildren().OfType(); foreach (var dimmable in dimmableAudio) dimmable.FadeIn(); } + public void OnResolved() + { + Game.ItemRescueMenu.MenuClosing += ItemRescueMenu_MenuClosing; + } + + private void ItemRescueMenu_MenuClosing() + { + GameRepo.Resume(); + } + + private void ItemRescueInteractZone_AreaEntered(Area3D area) + { + GameRepo.Pause(); + Game.ItemRescueMenu.Show(); + } + public override void FadeOutAudio() { var dimmableAudio = DimmableAudio.GetChildren().OfType(); diff --git a/Zennysoft.Game.Ma/src/map/dungeon/floors/Special Floors/Overworld.tscn b/Zennysoft.Game.Ma/src/map/dungeon/floors/Special Floors/Overworld.tscn index 8eac08e52..2cb8ccade 100644 --- a/Zennysoft.Game.Ma/src/map/dungeon/floors/Special Floors/Overworld.tscn +++ b/Zennysoft.Game.Ma/src/map/dungeon/floors/Special Floors/Overworld.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=558 format=4 uid="uid://dvnc26rebk6o0"] +[gd_scene load_steps=559 format=4 uid="uid://dvnc26rebk6o0"] [ext_resource type="Script" uid="uid://cuhfkyh3d7noa" path="res://src/map/dungeon/code/Overworld.cs" id="1_5hmt3"] [ext_resource type="Texture2D" uid="uid://co6h8vyi11sl2" path="res://src/map/overworld/Models/Overworld_CLOUD_RINGS_INNER_63.png" id="2_g6b7b"] @@ -10255,6 +10255,9 @@ shadow_mesh = SubResource("ArrayMesh_1annr") [sub_resource type="BoxShape3D" id="BoxShape3D_q7hpd"] size = Vector3(2.49086, 4.52832, 1) +[sub_resource type="BoxShape3D" id="BoxShape3D_5fm5y"] +size = Vector3(5.40659, 4.93652, 3.9856) + [node name="Overworld" type="Node3D"] script = ExtResource("1_5hmt3") @@ -11204,6 +11207,15 @@ skeleton = NodePath("") transform = Transform3D(0.943674, 0, -0.330877, 0, 1, 0, 0.330877, 0, 0.943674, -0.0489807, -0.637752, -0.318357) shape = SubResource("BoxShape3D_q7hpd") +[node name="ItemRescueInteractZone" type="Area3D" parent="."] +unique_name_in_owner = true +collision_layer = 256 +collision_mask = 256 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="ItemRescueInteractZone"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -280.996, 2.8715, 88.7621) +shape = SubResource("BoxShape3D_5fm5y") + [editable path="Node3D/Actors/Rat"] [editable path="Node3D/Actors/Clalo"] [editable path="Node3D/Actors/Caretaker of Saints"] diff --git a/Zennysoft.Game.Ma/src/player/Player.cs b/Zennysoft.Game.Ma/src/player/Player.cs index 3e9fb6911..fb2e0739c 100644 --- a/Zennysoft.Game.Ma/src/player/Player.cs +++ b/Zennysoft.Game.Ma/src/player/Player.cs @@ -158,9 +158,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide { PlayerFXAnimations.Play("RESET"); - foreach (var item in Inventory.Items) - Inventory.Remove(item); - + Inventory.Items.Clear(); HealthComponent.Reset(); VTComponent.Reset(); AttackComponent.Reset(); @@ -281,6 +279,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide HealthComponent.RaiseMaximumHP(equipable.BonusHP, false); VTComponent.RaiseMaximumVT(equipable.BonusVT, false); + //if (equipable.Augment != null) + // Augment(equipable.Augment, equipable); EquipmentComponent.Equip(equipable); SfxDatabase.Instance.Play(SoundEffect.Equip); @@ -293,6 +293,9 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide HealthComponent.SetMaximumHealth(HealthComponent.MaximumHP.Value - equipable.BonusHP); VTComponent.SetMaximumVT(VTComponent.MaximumVT.Value - equipable.BonusVT); + //if (equipable.Augment != null) + // Deaugment(equipable.Augment); + EquipmentComponent.Unequip(equipable); SfxDatabase.Instance.Play(SoundEffect.Unequip); @@ -300,6 +303,39 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide PersuaderCrosshair.Hide(); } + //public void ApplyNewAugment(Jewel jewel, EquipableItem equipableItem) + //{ + // _player.Inventory.Remove(jewel); + // jewel.ApplyAugment((dynamic)equipableItem); + + // if (!_player.EquipmentComponent.IsItemEquipped(equipableItem)) + // return; + + // if (jewel.Stats.JewelTag == JewelTags.IncreaseEXPGain) + // _player.ExperiencePointsComponent.ModifyExpGainRate(_player.ExperiencePointsComponent.ExpGainRate.Value + 0.25f); + //} + + private void Augment(IAugmentItem augment, EquipableItem equipable) + { + var jewel = augment as Jewel; + switch (augment.Augment) + { + case JewelTags.IncreaseEXPGain: + ExperiencePointsComponent.ModifyExpGainRate(ExperiencePointsComponent.ExpGainRate.Value + 0.25f); + break; + } + } + + private void Deaugment(Augment augment) + { + switch (augment.AugmentTag) + { + case JewelTags.IncreaseEXPGain: + ExperiencePointsComponent.ModifyExpGainRate(ExperiencePointsComponent.ExpGainRate.Value - 0.25f); + break; + } + } + private static Vector3 GlobalInputVector { get @@ -440,7 +476,6 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide PlayerBinding.Dispose(); Hitbox.AreaEntered -= Hitbox_AreaEntered; CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered; - HealthComponent.HealthReachedZero -= Die; HealthTimer.Timeout -= OnHealthTimerTimeout; HealthComponent.CurrentHP.Changed -= InverseHPToAttackPowerSync; HealthComponent.HealthReachedZero -= Die; 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 c6b71bc65..30fb57775 100644 --- a/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs +++ b/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.cs @@ -18,6 +18,8 @@ public partial class InGameUI : Control, IInGameUI [Node] public IInventoryMenu InventoryMenu { get; set; } = default!; + [Node] public ItemRescueMenu ItemRescueMenu { get; set; } = default!; + [Node] public IPlayerInfoUI PlayerInfoUI { get; set; } = default!; [Node] public InventoryMessageUI InventoryMessageUI { get; set; } = default!; diff --git a/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.tscn b/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.tscn index 0bd7ec765..1eb8c2462 100644 --- a/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.tscn +++ b/Zennysoft.Game.Ma/src/ui/in_game_ui/InGameUI.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=11 format=3 uid="uid://b1muxus5qdbeu"] +[gd_scene load_steps=12 format=3 uid="uid://b1muxus5qdbeu"] [ext_resource type="Script" uid="uid://dlq2mkhl4pe7a" path="res://src/ui/in_game_ui/InGameUI.cs" id="1_sc13i"] [ext_resource type="PackedScene" uid="uid://bwbofurcvf3yh" path="res://src/minimap/Minimap.tscn" id="2_6sfje"] @@ -9,6 +9,7 @@ [ext_resource type="PackedScene" uid="uid://8f3dk16nj0dn" path="res://src/menu/DebugMenu.tscn" id="7_llomk"] [ext_resource type="Texture2D" uid="uid://bj4p4qxb1mj3q" path="res://src/ui/player_ui/Assets/panel rough draft.png" id="7_ur8ag"] [ext_resource type="PackedScene" uid="uid://c3e6hbctay1us" path="res://src/ui/inventory_menu/InventoryMenu2.tscn" id="9_ur8ag"] +[ext_resource type="PackedScene" uid="uid://dwa7o6hkkwjg1" path="res://src/ui/inventory_menu/ItemRescueMenu.tscn" id="10_higkc"] [sub_resource type="StyleBoxLine" id="StyleBoxLine_ur8ag"] color = Color(0.792157, 0.698039, 0.643137, 1) @@ -147,3 +148,8 @@ size_flags_vertical = 3 [node name="InventoryMenu" parent="." instance=ExtResource("9_ur8ag")] unique_name_in_owner = true layout_mode = 1 + +[node name="ItemRescueMenu" parent="." instance=ExtResource("10_higkc")] +unique_name_in_owner = true +visible = false +layout_mode = 1 diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs deleted file mode 100644 index fff258e42..000000000 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs +++ /dev/null @@ -1,333 +0,0 @@ -using Chickensoft.AutoInject; -using Chickensoft.Introspection; -using Godot; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Zennysoft.Ma.Adapter; - -namespace Zennysoft.Game.Ma; - -[Meta(typeof(IAutoNode))] -public partial class InventoryMenu : Control, IInventoryMenu -{ - public override void _Notification(int what) => this.Notify(what); - - [Node] public VBoxContainer ItemsPage { get; set; } - - [Node] public Label ATKValue { get; set; } - [Node] public Label ATKBonusLabel { get; set; } - [Node] public Label DEFValue { get; set; } - [Node] public Label DEFBonusLabel { get; set; } - - [Node] public Button UseButton { get; set; } - [Node] public Button ThrowButton { get; set; } - [Node] public Button DropButton { get; set; } - - [Node] public Label ItemDescriptionTitle { get; set; } - [Node] public Label UseItemPrompt { get; set; } - [Node] public Label ItemEffectLabel { get; set; } - - [Node] public ItemSlot ItemSlot1 { get; set; } - [Node] public ItemSlot ItemSlot2 { get; set; } - [Node] public ItemSlot ItemSlot3 { get; set; } - [Node] public ItemSlot ItemSlot4 { get; set; } - [Node] public ItemSlot ItemSlot5 { get; set; } - [Node] public ItemSlot ItemSlot6 { get; set; } - [Node] public ItemSlot ItemSlot7 { get; set; } - [Node] public ItemSlot ItemSlot8 { get; set; } - [Node] public ItemSlot ItemSlot9 { get; set; } - [Node] public ItemSlot ItemSlot10 { get; set; } - [Node] public ItemSlot ItemSlot11 { get; set; } - [Node] public ItemSlot ItemSlot12 { get; set; } - [Node] public ItemSlot ItemSlot13 { get; set; } - [Node] public ItemSlot ItemSlot14 { get; set; } - [Node] public ItemSlot ItemSlot15 { get; set; } - [Node] public ItemSlot ItemSlot16 { get; set; } - [Node] public ItemSlot ItemSlot17 { get; set; } - [Node] public ItemSlot ItemSlot18 { get; set; } - [Node] public ItemSlot ItemSlot19 { get; set; } - [Node] public ItemSlot ItemSlot20 { get; set; } - - [Dependency] private IPlayer _player => this.DependOn(); - [Dependency] private IGame _game => this.DependOn(); - [Dependency] private IGameRepo _gameRepo => this.DependOn(); - - private List ItemSlots; - - private string ITEM_SLOT_SCENE = "res://src/ui/inventory_menu/ItemSlot.tscn"; - - private IItemSlot _currentlySelectedItem = null; - private bool _enableMenuSound = false; - - public void OnResolved() - { - ItemSlots = [ItemSlot1, ItemSlot2, ItemSlot3, ItemSlot4, ItemSlot5, ItemSlot6, ItemSlot7, ItemSlot8, ItemSlot9, ItemSlot10, ItemSlot11, ItemSlot12, ItemSlot13, ItemSlot14, ItemSlot15, ItemSlot16, ItemSlot17, ItemSlot18, ItemSlot19, ItemSlot20]; - _currentlySelectedItem = ItemSlot1; - foreach (var item in ItemSlots) - { - item.ItemPressed += Item_Pressed; - } - - _player.AttackComponent.CurrentAttack.Sync += Attack_Sync; - _player.AttackComponent.MaximumAttack.Sync += Attack_Sync; - _player.DefenseComponent.CurrentDefense.Sync += Defense_Sync; - _player.DefenseComponent.MaximumDefense.Sync += Defense_Sync; - _player.EquipmentComponent.EquipmentChanged += EquipmentComponent_EquipmentChanged; - _player.Inventory.InventoryChanged += Inventory_InventoryChanged; - - UseButton.Pressed += UseButtonPressed; - ThrowButton.Pressed += ThrowButtonPressed; - DropButton.Pressed += DropButtonPressed; - - UseButton.FocusEntered += ActionButtonFocusChanged; - ThrowButton.FocusEntered += ActionButtonFocusChanged; - DropButton.FocusEntered += ActionButtonFocusChanged; - - VisibilityChanged += InventoryMenu_VisibilityChanged; - SetProcessUnhandledInput(false); - } - - private void ActionButtonFocusChanged() - { - if (!_enableMenuSound) - SfxDatabase.Instance.Play(SoundEffect.MoveUI); - } - - public override void _UnhandledInput(InputEvent @event) - { - if ((!Input.IsActionJustPressed(GameInputs.UiUp) && Input.IsActionPressed(GameInputs.UiUp)) || (!Input.IsActionJustPressed(GameInputs.UiDown) && Input.IsActionPressed(GameInputs.UiDown))) - AcceptEvent(); - - if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseItemPrompt.Visible)) - { - SfxDatabase.Instance.Play(SoundEffect.CancelUI); - AcceptEvent(); - HideUserActionPrompt(); - } - else if (Input.IsActionJustPressed(GameInputs.UiCancel)) - { - SfxDatabase.Instance.Play(SoundEffect.CancelUI); - AcceptEvent(); - _gameRepo.CloseInventory(); - } - - if (Input.IsActionJustPressed(GameInputs.InventorySort)) - { - var isChanged = _player.Inventory.Sort(_player.EquipmentComponent.EquippedWeapon.Value, _player.EquipmentComponent.EquippedArmor.Value, _player.EquipmentComponent.EquippedAccessory.Value, _player.EquipmentComponent.EquippedAmmo.Value); - if (!isChanged) - return; - - SfxDatabase.Instance.Play(SoundEffect.SortInventory); - Inventory_InventoryChanged(); - Item_ItemExitFocus(_currentlySelectedItem); - _currentlySelectedItem = ItemSlot1; - _currentlySelectedItem.GrabFocus(); - } - } - - private void InventoryMenu_VisibilityChanged() - { - if (Visible) - { - SetProcessUnhandledInput(true); - SfxDatabase.Instance.Play(SoundEffect.OpenInventory); - _currentlySelectedItem.GrabFocus(); - _enableMenuSound = true; - } - else - { - SetProcessUnhandledInput(false); - SfxDatabase.Instance.Play(SoundEffect.CancelUI); - _enableMenuSound = false; - } - } - - private void Item_ItemExitFocus(IItemSlot itemSlot) - { - ItemDescriptionTitle.Text = string.Empty; - ItemEffectLabel.Text = string.Empty; - } - - private void Item_FocusEntered(IItemSlot itemSlot) - { - if (itemSlot.Item.Value == null) - return; - - if (_enableMenuSound) - SfxDatabase.Instance.Play(SoundEffect.MoveUI); - - ItemDescriptionTitle.Text = $"{itemSlot.Item.Value.ItemName}"; - ItemEffectLabel.Text = $"{itemSlot.Item.Value.Description}"; - _currentlySelectedItem = itemSlot; - AcceptEvent(); - } - - private void Item_Pressed(IItemSlot item) => DisplayUserActionPrompt(item.Item.Value); - - private async void Inventory_InventoryChanged() - { - foreach (var slot in ItemSlots) - { - slot.Visible = false; - } - - var itemsToDisplay = _player.Inventory.Items; - for (var i = 0; i < itemsToDisplay.Count; i++) - { - ItemSlots[i].Item.OnNext(itemsToDisplay[i]); - ItemSlots[i].Visible = true; - } - - if (!_player.Inventory.Items.Contains(_currentlySelectedItem.Item.Value)) - { - _currentlySelectedItem.Item.OnNext(null); - var elementToSelect = Mathf.Max(0, ItemSlots.IndexOf(_currentlySelectedItem) - 1); - _currentlySelectedItem = ItemSlots.ElementAt(elementToSelect); - _currentlySelectedItem.GrabFocus(); - } - } - - private void Attack_Sync(int obj) => ATKValue.Text = $"{_player.AttackComponent.CurrentAttack.Value}/{_player.AttackComponent.MaximumAttack.Value}"; - private void Defense_Sync(int obj) => DEFValue.Text = $"{_player.DefenseComponent.CurrentDefense.Value}/{_player.DefenseComponent.MaximumDefense.Value}"; - - private void EquipmentComponent_EquipmentChanged(EquipableItem equipableItem) - { - ATKBonusLabel.Text = $"{_player.EquipmentComponent.BonusAttack:+0;-#;\\.\\.\\.}"; - DEFBonusLabel.Text = $"{_player.EquipmentComponent.BonusDefense:+0;-#;\\.\\.\\.}"; - } - - private async void UseButtonPressed() - { - UseButton.Disabled = true; - if (_currentlySelectedItem.Item.Value is EquipableItem equipable) - await EquipOrUnequipItem(equipable); - else if (_currentlySelectedItem.Item.Value is Plastique plastique) - SetItem(); - else if (_currentlySelectedItem.Item.Value is Jewel jewel) - AugmentEquipment(jewel); - else - await _game.UseItem(_currentlySelectedItem.Item.Value); - UseButton.Disabled = false; - - - HideUserActionPrompt(); - await ShowInventoryInfo(); - await ToSignal(GetTree().CreateTimer(1f), "timeout"); - } - - private async void SetItem() - { - _game.SetItem(_currentlySelectedItem.Item.Value); - _player.Inventory.Remove(_currentlySelectedItem.Item.Value); - HideUserActionPrompt(); - await ShowInventoryInfo(); - _gameRepo.CloseInventory(); - } - - private async void ThrowButtonPressed() - { - _game.ThrowItem(_currentlySelectedItem.Item.Value); - _player.Inventory.Remove(_currentlySelectedItem.Item.Value); - HideUserActionPrompt(); - await ShowInventoryInfo(); - _gameRepo.CloseInventory(); - } - - private async void DropButtonPressed() - { - _game.DropItem(_currentlySelectedItem.Item.Value); - _player.Inventory.Remove(_currentlySelectedItem.Item.Value); - HideUserActionPrompt(); - await ShowInventoryInfo(); - _gameRepo.CloseInventory(); - } - - private void AugmentEquipment(Jewel jewel) - { - DisplayUserActionPrompt(jewel); - foreach (var item in ItemSlots) - { - item.Disabled = item.Item.Value is not Weapon && item.Item.Value is not Armor && item.Item.Value is not Accessory; - } - } - - private void DisplayUserActionPrompt(InventoryItem item) - { - SfxDatabase.Instance.Play(SoundEffect.SelectUI); - ItemDescriptionTitle.Hide(); - ItemEffectLabel.Hide(); - UseItemPrompt.Show(); - UseButton.Show(); - ThrowButton.Show(); - DropButton.Show(); - - if (item is EquipableItem equipable) - { - var isItemEquipped = _player.EquipmentComponent.IsItemEquipped(equipable); - UseButton.Text = isItemEquipped ? "Unequip" : "Equip"; - UseButton.Disabled = equipable.Glued; - ThrowButton.Disabled = isItemEquipped; - ThrowButton.FocusMode = isItemEquipped ? FocusModeEnum.None : FocusModeEnum.All; - DropButton.Disabled = isItemEquipped; - DropButton.FocusMode = isItemEquipped ? FocusModeEnum.None : FocusModeEnum.All; - - UseButton.GrabFocus(); - - if (!_player.CanEquipState && isItemEquipped) - UseButton.Disabled = true; - } - else if (item is Plastique plastique) - { - UseButton.Text = "Set"; - } - else - { - UseButton.Text = "Use"; - } - _enableMenuSound = false; - } - - private void HideUserActionPrompt() - { - UseItemPrompt.Hide(); - UseButton.Hide(); - ThrowButton.Hide(); - DropButton.Hide(); - UseButton.ReleaseFocus(); - ThrowButton.ReleaseFocus(); - DropButton.ReleaseFocus(); - _currentlySelectedItem.GrabFocus(); - _enableMenuSound = true; - } - - private async Task EquipOrUnequipItem(EquipableItem equipable) - { - if (_player.EquipmentComponent.IsItemEquipped(equipable)) - { - SfxDatabase.Instance.Play(SoundEffect.Unequip); - ItemEffectLabel.Text = $"{equipable.GetType().Name} unequipped."; - _player.Unequip(equipable); - } - else - { - SfxDatabase.Instance.Play(SoundEffect.Equip); - var itemSlot = _currentlySelectedItem; - ItemEffectLabel.Text = $"{equipable.GetType().Name} equipped."; - _player.Equip(equipable); - _currentlySelectedItem = itemSlot; - } - } - - private async Task ShowInventoryInfo() - { - ItemDescriptionTitle.Show(); - ItemEffectLabel.Show(); - } - - private enum InventoryPageNumber - { - FirstPage, - SecondPage - } -} diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs.uid b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs.uid deleted file mode 100644 index 68950098f..000000000 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bi1xopts68paw diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.tscn b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.tscn index 47f2c3da5..21cd8be65 100644 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.tscn +++ b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu.tscn @@ -1,6 +1,5 @@ -[gd_scene load_steps=21 format=3 uid="uid://dlj8qdg1c5048"] +[gd_scene load_steps=21 format=3 uid="uid://cbxw70qa7gifp"] -[ext_resource type="Script" uid="uid://bi1xopts68paw" path="res://src/ui/inventory_menu/InventoryMenu.cs" id="1_b6rkr"] [ext_resource type="PackedScene" uid="uid://c005nd0m2eim" path="res://src/ui/inventory_menu/ItemSlot.tscn" id="4_aiji3"] [ext_resource type="LabelSettings" uid="uid://wc363u5t1yi2" path="res://src/ui/label_settings/HeadingFont.tres" id="4_l0byb"] [ext_resource type="LabelSettings" uid="uid://cuuo43x72xcsc" path="res://src/ui/label_settings/MainTextBold.tres" id="7_vyrxm"] @@ -8,6 +7,345 @@ [ext_resource type="Theme" uid="uid://daxuhpmyxwxck" path="res://src/ui/inventory_menu/InventoryDialogueSelectionStyle.tres" id="8_khyvo"] [ext_resource type="LabelSettings" uid="uid://bgnwcs434ppkf" path="res://src/ui/label_settings/EbrimaText.tres" id="8_ldqki"] +[sub_resource type="CSharpScript" id="CSharpScript_xwkpe"] +script/source = "using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Godot; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Zennysoft.Ma.Adapter; + +namespace Zennysoft.Game.Ma; + +[Meta(typeof(IAutoNode))] +public partial class InventoryMenu : Control, IInventoryMenu +{ + public override void _Notification(int what) => this.Notify(what); + + [Node] public VBoxContainer ItemsPage { get; set; } + + [Node] public Label ATKValue { get; set; } + [Node] public Label ATKBonusLabel { get; set; } + [Node] public Label DEFValue { get; set; } + [Node] public Label DEFBonusLabel { get; set; } + + [Node] public Button UseButton { get; set; } + [Node] public Button ThrowButton { get; set; } + [Node] public Button DropButton { get; set; } + + [Node] public Label ItemDescriptionTitle { get; set; } + [Node] public Label UseItemPrompt { get; set; } + [Node] public Label ItemEffectLabel { get; set; } + + [Node] public ItemSlot ItemSlot1 { get; set; } + [Node] public ItemSlot ItemSlot2 { get; set; } + [Node] public ItemSlot ItemSlot3 { get; set; } + [Node] public ItemSlot ItemSlot4 { get; set; } + [Node] public ItemSlot ItemSlot5 { get; set; } + [Node] public ItemSlot ItemSlot6 { get; set; } + [Node] public ItemSlot ItemSlot7 { get; set; } + [Node] public ItemSlot ItemSlot8 { get; set; } + [Node] public ItemSlot ItemSlot9 { get; set; } + [Node] public ItemSlot ItemSlot10 { get; set; } + [Node] public ItemSlot ItemSlot11 { get; set; } + [Node] public ItemSlot ItemSlot12 { get; set; } + [Node] public ItemSlot ItemSlot13 { get; set; } + [Node] public ItemSlot ItemSlot14 { get; set; } + [Node] public ItemSlot ItemSlot15 { get; set; } + [Node] public ItemSlot ItemSlot16 { get; set; } + [Node] public ItemSlot ItemSlot17 { get; set; } + [Node] public ItemSlot ItemSlot18 { get; set; } + [Node] public ItemSlot ItemSlot19 { get; set; } + [Node] public ItemSlot ItemSlot20 { get; set; } + + [Dependency] private IPlayer _player => this.DependOn(); + [Dependency] private IGame _game => this.DependOn(); + [Dependency] private IGameRepo _gameRepo => this.DependOn(); + + private List ItemSlots; + + private string ITEM_SLOT_SCENE = \"res://src/ui/inventory_menu/ItemSlot.tscn\"; + + private IItemSlot _currentlySelectedItem = null; + private bool _enableMenuSound = false; + + public void OnResolved() + { + ItemSlots = [ItemSlot1, ItemSlot2, ItemSlot3, ItemSlot4, ItemSlot5, ItemSlot6, ItemSlot7, ItemSlot8, ItemSlot9, ItemSlot10, ItemSlot11, ItemSlot12, ItemSlot13, ItemSlot14, ItemSlot15, ItemSlot16, ItemSlot17, ItemSlot18, ItemSlot19, ItemSlot20]; + _currentlySelectedItem = ItemSlot1; + foreach (var item in ItemSlots) + { + item.ItemPressed += Item_Pressed; + } + + _player.AttackComponent.CurrentAttack.Sync += Attack_Sync; + _player.AttackComponent.MaximumAttack.Sync += Attack_Sync; + _player.DefenseComponent.CurrentDefense.Sync += Defense_Sync; + _player.DefenseComponent.MaximumDefense.Sync += Defense_Sync; + _player.EquipmentComponent.EquipmentChanged += EquipmentComponent_EquipmentChanged; + _player.Inventory.InventoryChanged += Inventory_InventoryChanged; + + UseButton.Pressed += UseButtonPressed; + ThrowButton.Pressed += ThrowButtonPressed; + DropButton.Pressed += DropButtonPressed; + + UseButton.FocusEntered += ActionButtonFocusChanged; + ThrowButton.FocusEntered += ActionButtonFocusChanged; + DropButton.FocusEntered += ActionButtonFocusChanged; + + VisibilityChanged += InventoryMenu_VisibilityChanged; + SetProcessUnhandledInput(false); + } + + private void ActionButtonFocusChanged() + { + if (!_enableMenuSound) + SfxDatabase.Instance.Play(SoundEffect.MoveUI); + } + + public override void _UnhandledInput(InputEvent @event) + { + if (!Visible) + return; + + if ((!Input.IsActionJustPressed(GameInputs.UiUp) && Input.IsActionPressed(GameInputs.UiUp)) || (!Input.IsActionJustPressed(GameInputs.UiDown) && Input.IsActionPressed(GameInputs.UiDown))) + AcceptEvent(); + + if (Input.IsActionJustPressed(GameInputs.UiCancel) && (UseItemPrompt.Visible)) + { + SfxDatabase.Instance.Play(SoundEffect.CancelUI); + AcceptEvent(); + HideUserActionPrompt(); + } + else if (Input.IsActionJustPressed(GameInputs.UiCancel)) + { + SfxDatabase.Instance.Play(SoundEffect.CancelUI); + AcceptEvent(); + _gameRepo.CloseInventory(); + } + + if (Input.IsActionJustPressed(GameInputs.InventorySort)) + { + var isChanged = _player.Inventory.Sort(_player.EquipmentComponent.EquippedWeapon.Value, _player.EquipmentComponent.EquippedArmor.Value, _player.EquipmentComponent.EquippedAccessory.Value, _player.EquipmentComponent.EquippedAmmo.Value); + if (!isChanged) + return; + + SfxDatabase.Instance.Play(SoundEffect.SortInventory); + Inventory_InventoryChanged(); + Item_ItemExitFocus(_currentlySelectedItem); + _currentlySelectedItem = ItemSlot1; + _currentlySelectedItem.GrabFocus(); + } + } + + private void InventoryMenu_VisibilityChanged() + { + if (Visible) + { + SetProcessUnhandledInput(true); + SfxDatabase.Instance.Play(SoundEffect.OpenInventory); + _currentlySelectedItem.GrabFocus(); + _enableMenuSound = true; + } + else + { + SetProcessUnhandledInput(false); + SfxDatabase.Instance.Play(SoundEffect.CancelUI); + _enableMenuSound = false; + } + } + + private void Item_ItemExitFocus(IItemSlot itemSlot) + { + ItemDescriptionTitle.Text = string.Empty; + ItemEffectLabel.Text = string.Empty; + } + + private void Item_FocusEntered(IItemSlot itemSlot) + { + if (itemSlot.Item.Value == null) + return; + + if (_enableMenuSound) + SfxDatabase.Instance.Play(SoundEffect.MoveUI); + + ItemDescriptionTitle.Text = $\"{itemSlot.Item.Value.ItemName}\"; + ItemEffectLabel.Text = $\"{itemSlot.Item.Value.Description}\"; + _currentlySelectedItem = itemSlot; + AcceptEvent(); + } + + private void Item_Pressed(IItemSlot item) => DisplayUserActionPrompt(item.Item.Value); + + private async void Inventory_InventoryChanged() + { + foreach (var slot in ItemSlots) + { + slot.Visible = false; + } + + var itemsToDisplay = _player.Inventory.Items; + for (var i = 0; i < itemsToDisplay.Count; i++) + { + ItemSlots[i].Item.OnNext(itemsToDisplay[i]); + ItemSlots[i].Visible = true; + } + + if (!_player.Inventory.Items.Contains(_currentlySelectedItem.Item.Value)) + { + _currentlySelectedItem.Item.OnNext(null); + var elementToSelect = Mathf.Max(0, ItemSlots.IndexOf(_currentlySelectedItem) - 1); + _currentlySelectedItem = ItemSlots.ElementAt(elementToSelect); + _currentlySelectedItem.GrabFocus(); + } + } + + private void Attack_Sync(int obj) => ATKValue.Text = $\"{_player.AttackComponent.CurrentAttack.Value}/{_player.AttackComponent.MaximumAttack.Value}\"; + private void Defense_Sync(int obj) => DEFValue.Text = $\"{_player.DefenseComponent.CurrentDefense.Value}/{_player.DefenseComponent.MaximumDefense.Value}\"; + + private void EquipmentComponent_EquipmentChanged(EquipableItem equipableItem) + { + ATKBonusLabel.Text = $\"{_player.EquipmentComponent.BonusAttack:+0;-#;\\\\.\\\\.\\\\.}\"; + DEFBonusLabel.Text = $\"{_player.EquipmentComponent.BonusDefense:+0;-#;\\\\.\\\\.\\\\.}\"; + } + + private async void UseButtonPressed() + { + UseButton.Disabled = true; + if (_currentlySelectedItem.Item.Value is EquipableItem equipable) + await EquipOrUnequipItem(equipable); + else if (_currentlySelectedItem.Item.Value is Plastique plastique) + SetItem(); + else if (_currentlySelectedItem.Item.Value is Jewel jewel) + AugmentEquipment(jewel); + else + await _game.UseItem(_currentlySelectedItem.Item.Value); + UseButton.Disabled = false; + + + HideUserActionPrompt(); + await ShowInventoryInfo(); + await ToSignal(GetTree().CreateTimer(1f), \"timeout\"); + } + + private async void SetItem() + { + _game.SetItem(_currentlySelectedItem.Item.Value); + _player.Inventory.Remove(_currentlySelectedItem.Item.Value); + HideUserActionPrompt(); + await ShowInventoryInfo(); + _gameRepo.CloseInventory(); + } + + private async void ThrowButtonPressed() + { + _game.ThrowItem(_currentlySelectedItem.Item.Value); + _player.Inventory.Remove(_currentlySelectedItem.Item.Value); + HideUserActionPrompt(); + await ShowInventoryInfo(); + _gameRepo.CloseInventory(); + } + + private async void DropButtonPressed() + { + _game.DropItem(_currentlySelectedItem.Item.Value); + _player.Inventory.Remove(_currentlySelectedItem.Item.Value); + HideUserActionPrompt(); + await ShowInventoryInfo(); + _gameRepo.CloseInventory(); + } + + private void AugmentEquipment(Jewel jewel) + { + DisplayUserActionPrompt(jewel); + foreach (var item in ItemSlots) + { + item.Disabled = item.Item.Value is not Weapon && item.Item.Value is not Armor && item.Item.Value is not Accessory; + } + } + + private void DisplayUserActionPrompt(InventoryItem item) + { + SfxDatabase.Instance.Play(SoundEffect.SelectUI); + ItemDescriptionTitle.Hide(); + ItemEffectLabel.Hide(); + UseItemPrompt.Show(); + UseButton.Show(); + ThrowButton.Show(); + DropButton.Show(); + + if (item is EquipableItem equipable) + { + var isItemEquipped = _player.EquipmentComponent.IsItemEquipped(equipable); + UseButton.Text = isItemEquipped ? \"Unequip\" : \"Equip\"; + UseButton.Disabled = equipable.Glued; + ThrowButton.Disabled = isItemEquipped; + ThrowButton.FocusMode = isItemEquipped ? FocusModeEnum.None : FocusModeEnum.All; + DropButton.Disabled = isItemEquipped; + DropButton.FocusMode = isItemEquipped ? FocusModeEnum.None : FocusModeEnum.All; + + UseButton.GrabFocus(); + + if (!_player.CanEquipState && isItemEquipped) + UseButton.Disabled = true; + } + else if (item is Plastique plastique) + { + UseButton.Text = \"Set\"; + } + else + { + UseButton.Text = \"Use\"; + } + _enableMenuSound = false; + } + + private void HideUserActionPrompt() + { + UseItemPrompt.Hide(); + UseButton.Hide(); + ThrowButton.Hide(); + DropButton.Hide(); + UseButton.ReleaseFocus(); + ThrowButton.ReleaseFocus(); + DropButton.ReleaseFocus(); + _currentlySelectedItem.GrabFocus(); + _enableMenuSound = true; + } + + private async Task EquipOrUnequipItem(EquipableItem equipable) + { + if (_player.EquipmentComponent.IsItemEquipped(equipable)) + { + SfxDatabase.Instance.Play(SoundEffect.Unequip); + ItemEffectLabel.Text = $\"{equipable.GetType().Name} unequipped.\"; + _player.Unequip(equipable); + } + else + { + SfxDatabase.Instance.Play(SoundEffect.Equip); + var itemSlot = _currentlySelectedItem; + ItemEffectLabel.Text = $\"{equipable.GetType().Name} equipped.\"; + _player.Equip(equipable); + _currentlySelectedItem = itemSlot; + } + } + + private async Task ShowInventoryInfo() + { + ItemDescriptionTitle.Show(); + ItemEffectLabel.Show(); + } + + private enum InventoryPageNumber + { + FirstPage, + SecondPage + } +} +" + [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_unikd"] blend_mode = 4 @@ -47,7 +385,7 @@ grow_vertical = 2 size_flags_horizontal = 3 size_flags_vertical = 3 mouse_filter = 2 -script = ExtResource("1_b6rkr") +script = SubResource("CSharpScript_xwkpe") [node name="BG" type="ColorRect" parent="."] material = SubResource("CanvasItemMaterial_unikd") diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.cs b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.cs index 702964872..8e64bac65 100644 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.cs +++ b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.cs @@ -38,6 +38,10 @@ public partial class InventoryMenu2 : Control, IInventoryMenu private IItemSlot _currentlySelected; + private bool _augmentMode = false; + + private Jewel _augmentingJewel; + #region ItemSlots [Node] public IItemSlot ItemSlot01 { get; set; } [Node] public IItemSlot ItemSlot02 { get; set; } @@ -91,7 +95,7 @@ public partial class InventoryMenu2 : Control, IInventoryMenu slot.ItemSelected += Slot_FocusEntered; slot.ItemPressed += Slot_ItemPressed; } - VisibilityChanged += InventoryMenu_VisibilityChanged; + VisibilityChanged += ResetInventoryState; InteractButton.Pressed += InteractButton_Pressed; ThrowButton.Pressed += ThrowButton_Pressed; DropButton.Pressed += DropButton_Pressed; @@ -103,7 +107,12 @@ public partial class InventoryMenu2 : Control, IInventoryMenu if (_currentlySelected != null) { var item = _currentlySelected.Item.Value; - if (item is EquipableItem equipable) + if (_augmentMode) + { + //_player.AugmentItem(_augmentingJewel, item as EquipableItem); + ResetInventoryState(); + } + else if (item is EquipableItem equipable) { if (_player.EquipmentComponent.IsItemEquipped(equipable)) _player.Unequip(equipable); @@ -116,6 +125,11 @@ public partial class InventoryMenu2 : Control, IInventoryMenu } else if (item is Plastique plastique) _game.SetItem(plastique); + else if (item is Jewel jewel) + { + _augmentMode = true; + AugmentMode(jewel); + } else _game.UseItem(_currentlySelected.Item.Value); @@ -148,6 +162,7 @@ public partial class InventoryMenu2 : Control, IInventoryMenu if (ActionPanel.Visible && Input.IsActionJustPressed(GameInputs.Interact)) { CloseActionMenu(); + _augmentMode = false; SfxDatabase.Instance.Play(SoundEffect.CancelUI); GetViewport().SetInputAsHandled(); } @@ -175,7 +190,7 @@ public partial class InventoryMenu2 : Control, IInventoryMenu { _player.Inventory.Sort(_player.EquipmentComponent.EquippedWeapon.Value, _player.EquipmentComponent.EquippedArmor.Value, _player.EquipmentComponent.EquippedAccessory.Value, _player.EquipmentComponent.EquippedAmmo.Value); SfxDatabase.Instance.Play(SoundEffect.SortInventory); - InventoryMenu_VisibilityChanged(); + ResetInventoryState(); } } @@ -190,7 +205,14 @@ public partial class InventoryMenu2 : Control, IInventoryMenu ThrowButton.FocusMode = FocusModeEnum.All; DropButton.FocusMode = FocusModeEnum.All; - if (item is EquipableItem equipable) + if (_augmentMode) + { + InteractButton.Text = "Augment"; + ThrowButton.Disabled = true; + DropButton.Disabled = true; + InteractButton.GrabFocus(); + } + else if (item is EquipableItem equipable) { var itemIsEquipped = _player.EquipmentComponent.IsItemEquipped(equipable); InteractButton.Text = itemIsEquipped ? "Unequip" : "Equip"; @@ -212,6 +234,11 @@ public partial class InventoryMenu2 : Control, IInventoryMenu InteractButton.FocusMode = FocusModeEnum.None; ThrowButton.GrabFocus(); } + else if (item is Jewel jewel) + { + InteractButton.Text = "Augment"; + InteractButton.GrabFocus(); + } else { InteractButton.Text = "Use"; @@ -221,19 +248,31 @@ public partial class InventoryMenu2 : Control, IInventoryMenu ActionPanel.Show(); } - private void InventoryMenu_VisibilityChanged() + private void ResetInventoryState() { + _augmentMode = false; + foreach (var item in ItemSlots) + { item.Hide(); + item.Disabled = true; + item.FocusMode = FocusModeEnum.None; + } foreach (var item in ItemCountLabels) item.Text = string.Empty; + ItemName.Text = string.Empty; + ItemFlavor.Text = string.Empty; + ItemStats.Text = string.Empty; + for (var i = 0; i < _player.Inventory.Items.Count; i++) { var item = _player.Inventory.Items[i]; ItemSlots[i].Item.OnNext(item); + ItemSlots[i].FocusMode = FocusModeEnum.All; + ItemSlots[i].Disabled = false; ItemSlots[i].Show(); ItemSlots[i].SetItemEquipmentStatus(_player.EquipmentComponent.IsItemEquipped(item)); if (item is IStackable stackable) @@ -256,6 +295,25 @@ public partial class InventoryMenu2 : Control, IInventoryMenu ItemFlavor.Text = item.Description; } + private void AugmentMode(Jewel jewel) + { + _augmentingJewel = jewel; + + foreach (var item in ItemSlots) + { + item.Disabled = true; + item.FocusMode = FocusModeEnum.None; + if (item.Item.Value is EquipableItem equipable && equipable.Augment == null) + { + item.Disabled = false; + item.FocusMode = FocusModeEnum.All; + } + } + + var itemToSelect = ItemSlots.First(x => !x.Disabled); + itemToSelect.GrabFocus(); + } + private void CloseActionMenu() { _currentlySelected.GrabFocus(); diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.tscn b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.tscn index d9b8d6bd0..01e24ed8b 100644 --- a/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.tscn +++ b/Zennysoft.Game.Ma/src/ui/inventory_menu/InventoryMenu2.tscn @@ -22,6 +22,7 @@ outline_color = Color(0, 0, 0, 1) bg_color = Color(0, 0, 0, 0.745098) [node name="InventoryMenu2" type="Control"] +process_mode = 2 visible = false layout_mode = 3 anchors_preset = 15 diff --git a/Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.cs b/Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.cs new file mode 100644 index 000000000..4cb05f1ae --- /dev/null +++ b/Zennysoft.Game.Ma/src/ui/inventory_menu/ItemRescueMenu.cs @@ -0,0 +1,203 @@ +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Godot; +using System; +using System.Collections.Generic; +using System.Linq; +using Zennysoft.Game.Implementation; +using Zennysoft.Game.Ma; +using Zennysoft.Ma.Adapter; + +[Meta(typeof(IAutoNode))] +public partial class ItemRescueMenu : Control +{ + public override void _Notification(int what) => this.Notify(what); + + [Dependency] private IPlayer _player => this.DependOn(); + + [Dependency] private IGame _game => this.DependOn(); + + [Dependency] private IGameRepo _gameRepo => this.DependOn(); + + [Node] public Label ItemName { get; set; } + + [Node] public Label ItemFlavor { get; set; } + + [Node] public Label ItemStats { get; set; } + + [Node] public Button InteractButton { get; set; } + + [Node] public Button DropButton { get; set; } + + [Node] public Control ActionPanel { get; set; } + + private List ItemSlots; + + private List