From b5798e7bc06f24e7996534b742cfc5adba59ef19 Mon Sep 17 00:00:00 2001 From: Zenny Date: Mon, 9 Sep 2024 23:05:44 -0700 Subject: [PATCH] Fix up equipping inventory items, fill out the rest of the inventory labels --- src/enemy/Enemy.cs | 4 +- src/enemy/EnemyStatInfo.cs | 13 +- src/game/Game.cs | 4 +- src/game/IGameRepo.cs | 94 +++++++++++---- src/inventory_menu/InventoryMenu.cs | 124 ++++++++++++++++---- src/inventory_menu/InventoryMenu.tscn | 2 +- src/inventory_menu/ItemSlot.cs | 72 +++++++++++- src/items/{IEquippable.cs => IEquipable.cs} | 2 +- src/items/accessory/Accessory.cs | 2 +- src/items/armor/Armor.cs | 2 +- src/items/weapons/Weapon.cs | 2 +- src/player/Player.cs | 6 +- src/player/Player.tscn | 13 +- src/player/PlayerData.cs | 28 +---- src/player/PlayerStatInfo.cs | 58 ++++++++- src/system/stats/DamageCalculator.cs | 8 +- src/system/stats/ICharacterStats.cs | 14 ++- 17 files changed, 340 insertions(+), 108 deletions(-) rename src/items/{IEquippable.cs => IEquipable.cs} (50%) diff --git a/src/enemy/Enemy.cs b/src/enemy/Enemy.cs index ea06ed01..826ee185 100644 --- a/src/enemy/Enemy.cs +++ b/src/enemy/Enemy.cs @@ -181,9 +181,9 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide var rng = new RandomNumberGenerator(); rng.Randomize(); var roll = rng.Randf(); - if (roll <= GameRepo.EquippedWeapon.WeaponInfo.Luck) + if (roll <= GameRepo.EquippedWeapon.Value.WeaponInfo.Luck) isCriticalHit = true; - var damage = DamageCalculator.CalculatePlayerDamage(hitBox.Damage, hitBox.GetParent().PlayerStatInfo, EnemyStatInfo, GameRepo.EquippedWeapon.WeaponInfo, isCriticalHit); + var damage = DamageCalculator.CalculatePlayerDamage(hitBox.Damage, hitBox.GetParent().PlayerStatInfo, EnemyStatInfo, GameRepo.EquippedWeapon.Value.WeaponInfo, isCriticalHit); GD.Print($"Enemy Hit for {damage} damage."); EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(damage)); } diff --git a/src/enemy/EnemyStatInfo.cs b/src/enemy/EnemyStatInfo.cs index 78f9609d..53f76f75 100644 --- a/src/enemy/EnemyStatInfo.cs +++ b/src/enemy/EnemyStatInfo.cs @@ -5,14 +5,23 @@ namespace GameJamDungeon [GlobalClass] public partial class EnemyStatInfo : Resource, ICharacterStats { + [Export] + public double CurrentHP { get; set; } + [Export] public double MaximumHP { get; set; } [Export] - public int BaseAttack { get; set; } + public int CurrentAttack { get; set; } [Export] - public int BaseDefense { get; set; } + public int CurrentDefense { get; set; } + + [Export] + public int MaxAttack { get; set; } + + [Export] + public int MaxDefense { get; set; } [Export] public float Luck { get; set; } = 0.05f; diff --git a/src/game/Game.cs b/src/game/Game.cs index 3587f252..0494d918 100644 --- a/src/game/Game.cs +++ b/src/game/Game.cs @@ -91,9 +91,9 @@ public partial class Game : Node3D, IGame var currentFloor = Floors.ElementAt(_currentFloor); currentFloor.CallDeferred(MethodName.QueueFree, []); - if (GameRepo.EquippedWeapon.WeaponInfo != null && GameRepo.EquippedWeapon.WeaponInfo.WeaponTags.Contains(WeaponTag.BreaksOnChange)) + if (GameRepo.EquippedWeapon.Value.WeaponInfo != null && GameRepo.EquippedWeapon.Value.WeaponInfo.WeaponTags.Contains(WeaponTag.BreaksOnChange)) { - GameRepo.InventoryItems.Value.Remove(GameRepo.EquippedWeapon); + GameRepo.InventoryItems.Value.Remove(GameRepo.EquippedWeapon.Value); GameRepo.OnWeaponEquipped(new Weapon()); } diff --git a/src/game/IGameRepo.cs b/src/game/IGameRepo.cs index bcbec7cf..05fa260a 100644 --- a/src/game/IGameRepo.cs +++ b/src/game/IGameRepo.cs @@ -23,25 +23,29 @@ public interface IGameRepo : IDisposable void SetPlayerGlobalPosition(Vector3 playerGlobalPosition); + void SetPlayerStatInfo(PlayerStatInfo playerStatInfo); + public void OnWeaponEquipped(Weapon equippedItem); public void OnArmorEquipped(Armor equippedItem); public void OnAccessoryEquipped(Accessory equippedItem); - public Weapon EquippedWeapon { get; } + public AutoProp EquippedWeapon { get; } - public Armor EquippedArmor { get; } + public AutoProp EquippedArmor { get; } - public Accessory EquippedAccessory { get; } - - public AutoProp HPBarValue { get; } - - public AutoProp VTBarValue { get; } - - bool IsWithinDialogueSpace { get; set; } + public AutoProp EquippedAccessory { get; } public int MaxItemSize { get; } + + public AutoProp PlayerStatInfo { get; } + + public bool IsItemEquipped(IEquipable item); + + public void EquipItem(IEquipable item); + + public void UnequipItem(IEquipable item); } public class GameRepo : IGameRepo @@ -61,20 +65,16 @@ public class GameRepo : IGameRepo public IAutoProp IsPaused => _isPaused; private readonly AutoProp _isPaused; - private Weapon _equippedWeapon; - public Weapon EquippedWeapon => _equippedWeapon; + private AutoProp _equippedWeapon; + public AutoProp EquippedWeapon => _equippedWeapon; - private Armor _equippedArmor; + private AutoProp _equippedArmor; - public Armor EquippedArmor => _equippedArmor; + public AutoProp EquippedArmor => _equippedArmor; - private Accessory _equippedAccessory; + private AutoProp _equippedAccessory; - public Accessory EquippedAccessory => _equippedAccessory; - - public AutoProp HPBarValue { get; } - - public AutoProp VTBarValue { get; } + public AutoProp EquippedAccessory => _equippedAccessory; public bool IsWithinDialogueSpace { get; set; } @@ -82,16 +82,20 @@ public class GameRepo : IGameRepo private bool _disposedValue; + private AutoProp _playerStatInfo; + + public AutoProp PlayerStatInfo => _playerStatInfo; + public GameRepo() { _inventoryItems = new AutoProp>([]); _isInventoryScreenOpened = new AutoProp(false); _isPaused = new AutoProp(false); _playerGlobalPosition = new AutoProp(Vector3.Zero); - _equippedWeapon = new Weapon(); - HPBarValue = new AutoProp(0); - VTBarValue = new AutoProp(0); - IsWithinDialogueSpace = false; + _equippedWeapon = new AutoProp(new Weapon()); + _equippedArmor = new AutoProp(new Armor()); + _equippedAccessory = new AutoProp(new Accessory()); + _playerStatInfo = new AutoProp(new PlayerStatInfo()); } public void Pause() @@ -108,19 +112,21 @@ public class GameRepo : IGameRepo public void SetPlayerGlobalPosition(Vector3 playerGlobalPosition) => _playerGlobalPosition.OnNext(playerGlobalPosition); + public void SetPlayerStatInfo(PlayerStatInfo playerStatInfo) => _playerStatInfo.OnNext(playerStatInfo); + public void OnWeaponEquipped(Weapon equippedItem) { - _equippedWeapon = equippedItem; + _equippedWeapon.OnNext(equippedItem); } public void OnArmorEquipped(Armor equippedItem) { - _equippedArmor = equippedItem; + _equippedArmor.OnNext(equippedItem); } public void OnAccessoryEquipped(Accessory equippedItem) { - _equippedAccessory = equippedItem; + _equippedAccessory.OnNext(equippedItem); } public void OnGameEnded() @@ -129,6 +135,42 @@ public class GameRepo : IGameRepo Ended?.Invoke(); } + public bool IsItemEquipped(IEquipable item) + { + if (item is Weapon) + return EquippedWeapon.Value == item; + + if (item is Armor) + return EquippedArmor.Value == item; + + if (item is Accessory) + return EquippedAccessory.Value == item; + + return false; + } + + public void EquipItem(IEquipable item) + { + if (item is Weapon weapon) + OnWeaponEquipped(weapon); + + if (item is Armor armor) + OnArmorEquipped(armor); + + if (item is Accessory accessory) + OnAccessoryEquipped(accessory); + } + + public void UnequipItem(IEquipable item) + { + if (item == EquippedWeapon.Value) + OnWeaponEquipped(new Weapon()); + if (item == EquippedArmor.Value) + OnArmorEquipped(new Armor()); + if (item == EquippedAccessory.Value) + OnAccessoryEquipped(new Accessory()); + } + protected void Dispose(bool disposing) { if (!_disposedValue) diff --git a/src/inventory_menu/InventoryMenu.cs b/src/inventory_menu/InventoryMenu.cs index 8dbf6335..921cd74f 100644 --- a/src/inventory_menu/InventoryMenu.cs +++ b/src/inventory_menu/InventoryMenu.cs @@ -54,15 +54,65 @@ public partial class InventoryMenu : Control, IInventoryMenu private int _currentIndex = 0; - private ItemSlot[] ItemSlots => ItemsPage.GetChildren().OfType().ToArray(); - - private static LabelSettings ItemFont => GD.Load("res://src/ui/label_settings/MainTextRegular.tres"); - private static LabelSettings SelectedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontItalicized.tres"); - private static LabelSettings EquippedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontEquipped.tres"); - - private static LabelSettings SelectedEquippedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontSelectedEquipped.tres"); + private IItemSlot[] ItemSlots => ItemsPage.GetChildren().OfType().ToArray(); public void PopulateItems() + { + PopulatePlayerInfo(); + PopulateInventory(); + } + + public void PopulatePlayerInfo() + { + + FloorLabel.Text = $"Floor 0"; + + var currentLevel = GameRepo.PlayerStatInfo.Value.CurrentLevel; + CurrentLevelLabel.Text = $"Level {currentLevel:D2}"; + + var currentHP = GameRepo.PlayerStatInfo.Value.CurrentHP; + var maxHP = GameRepo.PlayerStatInfo.Value.MaximumHP; + + HPValue.Text = $"{currentHP}/{maxHP}"; + + var currentVT = GameRepo.PlayerStatInfo.Value.CurrentVT; + var maxVT = GameRepo.PlayerStatInfo.Value.MaximumVT; + + VTValue.Text = $"{currentVT}/{maxVT}"; + + var currentAttack = GameRepo.PlayerStatInfo.Value.CurrentAttack; + var maxAttack = GameRepo.PlayerStatInfo.Value.MaxAttack; + + ATKValue.Text = $"{currentAttack}/{maxAttack}"; + + var currentDefense = GameRepo.PlayerStatInfo.Value.CurrentDefense; + var maxDefense = GameRepo.PlayerStatInfo.Value.MaxDefense; + DEFValue.Text = $"{currentDefense}/{maxDefense}"; + + var atkBonus = GameRepo.PlayerStatInfo.Value.BonusAttack; + var defBonus = GameRepo.PlayerStatInfo.Value.BonusDefense; + + ATKBonusLabel.Text = atkBonus != 0 ? $"{atkBonus}" : "..."; + DEFBonusLabel.Text = defBonus != 0 ? $"{defBonus}" : "..."; + + // TODO: Change font style when EXP Bonus effect is active + var currentExp = GameRepo.PlayerStatInfo.Value.CurrentEXP; + var expToNextLevel = GameRepo.PlayerStatInfo.Value.EXPToNextLevel; + EXPValue.Text = $"{currentExp}/{expToNextLevel}"; + + if (ItemSlots.Any()) + { + ItemDescriptionTitle.Text = $"{ItemSlots.ElementAtOrDefault(_currentIndex).Item.Info.Name}"; + ItemEffectLabel.Text = $"{ItemSlots.ElementAtOrDefault(_currentIndex).Item.Info.Description}"; + } + else + { + ItemDescriptionTitle.Text = string.Empty; + ItemEffectLabel.Text = string.Empty; + } + } + + private void PopulateInventory() { var inventory = GameRepo.InventoryItems.Value; var numberOfItemsToDisplay = _currentPageNumber == InventoryPageNumber.FirstPage ? Mathf.Min(inventory.Count, _itemsPerPage) : Mathf.Min(inventory.Count - _itemsPerPage, _itemsPerPage); @@ -88,15 +138,19 @@ public partial class InventoryMenu : Control, IInventoryMenu var item = inventory.ElementAt(i + indexToStart); var itemScene = GD.Load(ITEM_SLOT_SCENE); var itemSlot = itemScene.Instantiate(); + itemSlot.Item = item; ItemsPage.AddChildEx(itemSlot); - itemSlot.ItemName.Text = item.Info.Name; - itemSlot.ItemTexture.Texture = item.Info.Texture; - itemSlot.EquipBonus.Text = "..."; + if (itemSlot.Item is IEquipable equipable && GameRepo.IsItemEquipped(equipable)) + itemSlot.SetEquippedItemStyle(); } if (ItemSlots.Any()) - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = SelectedItemFont; + { + ItemSlots.ElementAt(_currentIndex).SetSelectedItemStyle(); + if (ItemSlots.ElementAt(_currentIndex).Item is IEquipable equipable && GameRepo.IsItemEquipped(equipable)) + ItemSlots.ElementAt(_currentIndex).SetEquippedSelectedItemStyle(); + } } public override void _UnhandledInput(InputEvent @event) @@ -120,31 +174,53 @@ public partial class InventoryMenu : Control, IInventoryMenu if (ItemSlots.Any() && Input.IsActionJustPressed(GameInputs.UiDown)) { - if (!inventory.Any() || _currentIndex + 1 >= _itemsPerPage) + if (!inventory.Any()) return; - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = ItemFont; - _currentIndex++; - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = SelectedItemFont; + var oldItem = ItemSlots.ElementAt(_currentIndex); + ItemSlots.ElementAt(_currentIndex).SetItemStyle(); + var index = new[] { _currentIndex + 1, _itemsPerPage - 1, ItemSlots.Count() - 1 }; + _currentIndex = index.Min(); + var newItem = ItemSlots.ElementAt(_currentIndex); + newItem.SetSelectedItemStyle(); + if (oldItem.Item is IEquipable equipable && GameRepo.IsItemEquipped(equipable)) + oldItem.SetEquippedItemStyle(); + if (newItem.Item is IEquipable newEquipable && GameRepo.IsItemEquipped(newEquipable)) + newItem.SetEquippedSelectedItemStyle(); } if (ItemSlots.Any() && Input.IsActionJustPressed(GameInputs.UiUp)) { - if (!inventory.Any() || _currentIndex <= 0) + if (!inventory.Any()) return; - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = ItemFont; - _currentIndex--; - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = SelectedItemFont; + var oldItem = ItemSlots.ElementAt(_currentIndex); + ItemSlots.ElementAt(_currentIndex).SetItemStyle(); + var index = new[] { _currentIndex - 1, 0 }; + _currentIndex = index.Max(); + var newItem = ItemSlots.ElementAt(_currentIndex); + newItem.SetSelectedItemStyle(); + if (oldItem.Item is IEquipable equipable && GameRepo.IsItemEquipped(equipable)) + oldItem.SetEquippedItemStyle(); + if (newItem.Item is IEquipable newEquipable && GameRepo.IsItemEquipped(newEquipable)) + newItem.SetEquippedSelectedItemStyle(); } if (ItemSlots.Any() && Input.IsActionJustPressed(GameInputs.UiAccept)) { - if (_currentPageNumber == InventoryPageNumber.FirstPage) + var itemSlot = ItemSlots[_currentIndex]; + if (itemSlot.Item is IEquipable equipableItem) { - var item = inventory.ElementAt(_currentIndex); - if (item is IEquippable) - ItemSlots.ElementAt(_currentIndex).ItemName.LabelSettings = EquippedItemFont; + if (GameRepo.IsItemEquipped(equipableItem)) + { + GameRepo.UnequipItem(equipableItem); + itemSlot.SetSelectedItemStyle(); + } + else + { + GameRepo.EquipItem(equipableItem); + itemSlot.SetEquippedSelectedItemStyle(); + } } } } @@ -153,7 +229,7 @@ public partial class InventoryMenu : Control, IInventoryMenu { foreach (var item in ItemSlots) { - ItemsPage.RemoveChild(item); + ItemsPage.RemoveChildEx(item); } } } diff --git a/src/inventory_menu/InventoryMenu.tscn b/src/inventory_menu/InventoryMenu.tscn index 538d61d7..2993051c 100644 --- a/src/inventory_menu/InventoryMenu.tscn +++ b/src/inventory_menu/InventoryMenu.tscn @@ -114,7 +114,7 @@ layout_mode = 2 [node name="PlayerInfo" type="VBoxContainer" parent="InventoryInfo/HBoxContainer"] layout_mode = 2 -theme_override_constants/separation = 40 +theme_override_constants/separation = 20 [node name="FloorBox" type="HBoxContainer" parent="InventoryInfo/HBoxContainer/PlayerInfo"] layout_mode = 2 diff --git a/src/inventory_menu/ItemSlot.cs b/src/inventory_menu/ItemSlot.cs index 8d76d5df..8db25a6d 100644 --- a/src/inventory_menu/ItemSlot.cs +++ b/src/inventory_menu/ItemSlot.cs @@ -1,15 +1,20 @@ using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; +using GameJamDungeon; using Godot; public interface IItemSlot : IHBoxContainer { - public Label EquipBonus { get; } + public IInventoryItem Item { get; set; } - public TextureRect ItemTexture { get; } + public void SetItemStyle(); - public Label ItemName { get; } + public void SetSelectedItemStyle(); + + public void SetEquippedItemStyle(); + + public void SetEquippedSelectedItemStyle(); } [Meta(typeof(IAutoNode))] @@ -17,9 +22,70 @@ public partial class ItemSlot : HBoxContainer, IItemSlot { public override void _Notification(int what) => this.Notify(what); + [Dependency] + public IGameRepo GameRepo => this.DependOn(); + [Node] public Label EquipBonus { get; set; } = default!; [Node] public TextureRect ItemTexture { get; set; } = default!; [Node] public Label ItemName { get; set; } = default!; + + private static LabelSettings ItemFont => GD.Load("res://src/ui/label_settings/MainTextRegular.tres"); + private static LabelSettings SelectedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontItalicized.tres"); + private static LabelSettings EquippedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontEquipped.tres"); + + private static LabelSettings SelectedEquippedItemFont => GD.Load("res://src/ui/label_settings/MainTextFontSelectedEquipped.tres"); + + public void OnReady() + { + ItemName.Text = Item.Info.Name; + EquipBonus.Text = "..."; + ItemTexture.Texture = Item.Info.Texture; + GameRepo.EquippedWeapon.Sync += EquippedWeapon_Sync; + GameRepo.EquippedArmor.Sync += EquippedArmor_Sync; + GameRepo.EquippedAccessory.Sync += EquippedAccessory_Sync; + } + + private void EquippedWeapon_Sync(Weapon obj) + { + if (Item is Weapon unequippedItem && unequippedItem != obj) + SetItemStyle(); + } + + private void EquippedArmor_Sync(Armor obj) + { + if (Item is Armor unequippedItem && unequippedItem != obj) + SetItemStyle(); + } + + private void EquippedAccessory_Sync(Accessory obj) + { + if (Item is Accessory unequippedItem && unequippedItem != obj) + SetItemStyle(); + } + + public void SetItemStyle() + { + ItemName.LabelSettings = ItemFont; + EquipBonus.LabelSettings = ItemFont; + } + public void SetSelectedItemStyle() + { + ItemName.LabelSettings = SelectedItemFont; + EquipBonus.LabelSettings = SelectedItemFont; + } + public void SetEquippedItemStyle() + { + ItemName.LabelSettings = EquippedItemFont; + EquipBonus.LabelSettings = EquippedItemFont; + } + + public void SetEquippedSelectedItemStyle() + { + ItemName.LabelSettings = SelectedEquippedItemFont; + EquipBonus.LabelSettings = SelectedEquippedItemFont; + } + + public IInventoryItem Item { get; set; } = default!; } diff --git a/src/items/IEquippable.cs b/src/items/IEquipable.cs similarity index 50% rename from src/items/IEquippable.cs rename to src/items/IEquipable.cs index b81e960d..9276fb3d 100644 --- a/src/items/IEquippable.cs +++ b/src/items/IEquipable.cs @@ -1,4 +1,4 @@ namespace GameJamDungeon { - public interface IEquippable; + public interface IEquipable; } diff --git a/src/items/accessory/Accessory.cs b/src/items/accessory/Accessory.cs index 43cc4f32..6fc73778 100644 --- a/src/items/accessory/Accessory.cs +++ b/src/items/accessory/Accessory.cs @@ -5,7 +5,7 @@ using Godot; using System.Linq; [Meta(typeof(IAutoNode))] -public partial class Accessory : Node3D, IInventoryItem, IEquippable +public partial class Accessory : Node3D, IInventoryItem, IEquipable { public override void _Notification(int what) => this.Notify(what); diff --git a/src/items/armor/Armor.cs b/src/items/armor/Armor.cs index 04489615..9ee8ec7d 100644 --- a/src/items/armor/Armor.cs +++ b/src/items/armor/Armor.cs @@ -5,7 +5,7 @@ using Godot; using System.Linq; [Meta(typeof(IAutoNode))] -public partial class Armor : Node3D, IInventoryItem, IEquippable +public partial class Armor : Node3D, IInventoryItem, IEquipable { public override void _Notification(int what) => this.Notify(what); diff --git a/src/items/weapons/Weapon.cs b/src/items/weapons/Weapon.cs index 99d7eb09..0ee56c7c 100644 --- a/src/items/weapons/Weapon.cs +++ b/src/items/weapons/Weapon.cs @@ -5,7 +5,7 @@ using Godot; using System.Linq; [Meta(typeof(IAutoNode))] -public partial class Weapon : Node3D, IInventoryItem, IEquippable +public partial class Weapon : Node3D, IInventoryItem, IEquipable { public Weapon() { diff --git a/src/player/Player.cs b/src/player/Player.cs index 62ec65eb..4f711c00 100644 --- a/src/player/Player.cs +++ b/src/player/Player.cs @@ -98,6 +98,8 @@ namespace GameJamDungeon GameRepo.SetPlayerGlobalPosition(GlobalPosition); GameRepo.PlayerGlobalPosition.Sync += OnPlayerPositionUpdated; + GameRepo.SetPlayerStatInfo(PlayerStatInfo); + _currentHP = new AutoProp(PlayerStatInfo.MaximumHP); _currentVT = new AutoProp(PlayerStatInfo.MaximumVT); _currentHP.Sync += OnHPChanged; @@ -119,7 +121,7 @@ namespace GameJamDungeon }) .Handle((in PlayerLogic.Output.Animations.Attack output) => { - var weaponInfo = GameRepo.EquippedWeapon.WeaponInfo; + var weaponInfo = GameRepo.EquippedWeapon.Value.WeaponInfo; var attackSpeed = (float)weaponInfo.AttackSpeed; AnimationPlayer.SetSpeedScale(attackSpeed); AnimationPlayer.Play("attack"); @@ -160,7 +162,7 @@ namespace GameJamDungeon var roll = rng.Randf(); if (roll <= enemy.EnemyStatInfo.Luck) isCriticalHit = true; - var damage = DamageCalculator.CalculateEnemyDamage(hitBox.Damage, PlayerStatInfo, enemy.EnemyStatInfo, GameRepo.EquippedArmor.ArmorInfo, isCriticalHit); + var damage = DamageCalculator.CalculateEnemyDamage(hitBox.Damage, PlayerStatInfo, enemy.EnemyStatInfo, GameRepo.EquippedArmor.Value.ArmorInfo, isCriticalHit); _currentHP.OnNext(_currentHP.Value - damage); GD.Print($"Player hit for {damage} damage."); } diff --git a/src/player/Player.tscn b/src/player/Player.tscn index fb2084ec..ee1724b1 100644 --- a/src/player/Player.tscn +++ b/src/player/Player.tscn @@ -15,10 +15,19 @@ [sub_resource type="Resource" id="Resource_up0v1"] script = ExtResource("2_n88di") +CurrentHP = 100.0 MaximumHP = 100.0 +CurrentVT = 90 MaximumVT = 90 -BaseAttack = 10 -BaseDefense = 5 +CurrentLevel = 1 +CurrentEXP = 0 +EXPToNextLevel = 100 +CurrentAttack = 12 +MaxAttack = 12 +CurrentDefense = 8 +MaxDefense = 8 +BonusAttack = 0 +BonusDefense = 0 [sub_resource type="BoxShape3D" id="BoxShape3D_wedu3"] diff --git a/src/player/PlayerData.cs b/src/player/PlayerData.cs index 0402dc38..7f728389 100644 --- a/src/player/PlayerData.cs +++ b/src/player/PlayerData.cs @@ -1,31 +1,7 @@ -using Chickensoft.Collections; -using Chickensoft.Serialization; -using Godot; -using System.Collections.Generic; - -namespace GameJamDungeon +namespace GameJamDungeon { public partial record PlayerData { - [Save("global_transform")] - public required Transform3D GlobalTransform { get; init; } - - [Save("state_machine")] - public required PlayerLogic StateMachine { get; init; } - - [Save("PlayerEquippedSword")] - public required IAutoProp EquippedWeapon { get; set; } - - [Save("PlayerInventory")] - public required InventoryItemInfo[] Inventory { get; set; } = new InventoryItemInfo[5]; - - [Save("PlayerStats")] - public required PlayerStatInfo PlayerStats { get; set; } - - [Save("CurrentHP")] - public required int CurrentHP { get; set; } - - [Save("CurrentVT")] - public required int CurrentVT { get; set; } + // TODO: Implement save system } } diff --git a/src/player/PlayerStatInfo.cs b/src/player/PlayerStatInfo.cs index c9dbe828..3305bbf3 100644 --- a/src/player/PlayerStatInfo.cs +++ b/src/player/PlayerStatInfo.cs @@ -1,4 +1,5 @@ -using Godot; +using Chickensoft.Collections; +using Godot; namespace GameJamDungeon { @@ -6,15 +7,62 @@ namespace GameJamDungeon public partial class PlayerStatInfo : Resource, ICharacterStats { [Export] - public double MaximumHP { get; set; } + public double CurrentHP { get => _currentHP.Value; set => _currentHP.OnNext(value); } [Export] - public int MaximumVT { get; set; } + public double MaximumHP { get => _maximumHP.Value; set => _maximumHP.OnNext(value); } [Export] - public int BaseAttack { get; set; } + public int CurrentVT { get => _currentVT.Value; set => _currentVT.OnNext(value); } [Export] - public int BaseDefense { get; set; } + public int MaximumVT { get => _maximumVT.Value; set => _maximumVT.OnNext(value); } + + [Export] + public int CurrentLevel { get => _currentLevel.Value; set => _currentLevel.OnNext(value); } + + + [Export] + public int CurrentEXP { get => _currentExp.Value; set => _currentExp.OnNext(value); } + + [Export] + public int EXPToNextLevel { get => _expToNextLevel.Value; set => _expToNextLevel.OnNext(value); } + + [Export] + public int CurrentAttack { get => _currentAttack.Value; set => _currentAttack.OnNext(value); } + + [Export] + public int MaxAttack { get => _maxAttack.Value; set => _maxAttack.OnNext(value); } + + [Export] + public int CurrentDefense { get => _currentDefense.Value; set => _currentDefense.OnNext(value); } + [Export] + public int MaxDefense { get => _maxDefense.Value; set => _maxDefense.OnNext(value); } + + [Export] + public int BonusAttack { get => _bonusAttack.Value; set => _bonusAttack.OnNext(value); } + + [Export] + public int BonusDefense { get => _bonusDefense.Value; set => _bonusDefense.OnNext(value); } + + // AutoProp backing data + private readonly AutoProp _currentHP = new AutoProp(0); + private readonly AutoProp _maximumHP = new AutoProp(0); + + private readonly AutoProp _currentVT = new AutoProp(0); + private readonly AutoProp _maximumVT = new AutoProp(0); + + private readonly AutoProp _currentExp = new AutoProp(0); + private readonly AutoProp _expToNextLevel = new AutoProp(0); + private readonly AutoProp _currentLevel = new AutoProp(0); + + private readonly AutoProp _currentAttack = new AutoProp(0); + private readonly AutoProp _currentDefense = new AutoProp(0); + + private readonly AutoProp _maxAttack = new AutoProp(0); + private readonly AutoProp _maxDefense = new AutoProp(0); + + private readonly AutoProp _bonusAttack = new AutoProp(0); + private readonly AutoProp _bonusDefense = new AutoProp(0); } } diff --git a/src/system/stats/DamageCalculator.cs b/src/system/stats/DamageCalculator.cs index 16d6172d..c0e06325 100644 --- a/src/system/stats/DamageCalculator.cs +++ b/src/system/stats/DamageCalculator.cs @@ -6,7 +6,7 @@ namespace GameJamDungeon { public static double CalculatePlayerDamage(int attackDamage, PlayerStatInfo playerStatInfo, EnemyStatInfo enemyStatInfo, WeaponInfo weapon, bool isCriticalHit) { - var baseDamage = attackDamage + playerStatInfo.BaseAttack; + var baseDamage = attackDamage + playerStatInfo.CurrentAttack; var hydricResistance = enemyStatInfo.HydricResistance; var igneousResistance = enemyStatInfo.IgneousResistance; var telluricResistance = enemyStatInfo.TelluricResistance; @@ -28,7 +28,7 @@ namespace GameJamDungeon var elementDDamage = (weapon.AeolicDamageBonus > 0 ? weapon.AeolicDamageBonus - aeolicResistance : 0) / 100; var elementEDamage = (weapon.FerrumDamageBonus > 0 ? weapon.FerrumDamageBonus - ferrumResistance : 0) / 100; var elementalBonusDamage = baseDamage + (baseDamage * elementADamage) + (baseDamage * elementBDamage) + (baseDamage * elementCDamage) + (baseDamage * elementDDamage) + (baseDamage * elementEDamage); - var calculatedDamage = elementalBonusDamage - enemyStatInfo.BaseDefense; + var calculatedDamage = elementalBonusDamage - enemyStatInfo.CurrentDefense; if (isCriticalHit) calculatedDamage *= 2; @@ -38,14 +38,14 @@ namespace GameJamDungeon public static double CalculateEnemyDamage(int attackDamage, PlayerStatInfo playerStatInfo, EnemyStatInfo enemyStatInfo, ArmorInfo armor, bool isCriticalHit) { - var baseDamage = attackDamage + enemyStatInfo.BaseAttack; + var baseDamage = attackDamage + enemyStatInfo.CurrentAttack; var elementADamage = (enemyStatInfo.BaseHydricDamageBonus > 0 ? enemyStatInfo.BaseHydricDamageBonus - armor.HydricResistance : 0) / 100; var elementBDamage = (enemyStatInfo.IgneousDamageBonus > 0 ? enemyStatInfo.IgneousDamageBonus - armor.IgneousResistance : 0) / 100; var elementCDamage = (enemyStatInfo.TelluricDamageBonus > 0 ? enemyStatInfo.TelluricDamageBonus - armor.TelluricResistance : 0) / 100; var elementDDamage = (enemyStatInfo.AeolicDamageBonus > 0 ? enemyStatInfo.AeolicDamageBonus - armor.AeolicResistance : 0) / 100; var elementEDamage = (enemyStatInfo.FerrumDamageBonus > 0 ? enemyStatInfo.FerrumDamageBonus - armor.FerrumResistance : 0) / 100; var elementalBonusDamage = baseDamage + (baseDamage * elementADamage) + (baseDamage * elementBDamage) + (baseDamage * elementCDamage) + (baseDamage * elementDDamage) + (baseDamage * elementEDamage); - var calculatedDamage = elementalBonusDamage - playerStatInfo.BaseDefense - (armor != null ? armor.Defense : 0); + var calculatedDamage = elementalBonusDamage - playerStatInfo.CurrentDefense - (armor != null ? armor.Defense : 0); if (isCriticalHit) calculatedDamage *= 2; diff --git a/src/system/stats/ICharacterStats.cs b/src/system/stats/ICharacterStats.cs index 36977890..0685555f 100644 --- a/src/system/stats/ICharacterStats.cs +++ b/src/system/stats/ICharacterStats.cs @@ -1,13 +1,17 @@ -using Godot; - -namespace GameJamDungeon +namespace GameJamDungeon { public interface ICharacterStats { + public double CurrentHP { get; } + public double MaximumHP { get; } - public int BaseAttack { get; } + public int CurrentAttack { get; } - public int BaseDefense { get; } + public int CurrentDefense { get; } + + public int MaxAttack { get; } + + public int MaxDefense { get; } } }