CharacterSheet.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEngine;
  4. namespace MazeGen
  5. {
  6. /// <summary>
  7. /// Represents a character's complete combat state: base stats, equipped items,
  8. /// temporary bonuses, and inventory. Both agents and monsters use this.
  9. /// </summary>
  10. public class CharacterSheet
  11. {
  12. private string name;
  13. private string gameobjectName;
  14. private CharacterStats _baseStats;
  15. private Weapon _equippedWeapon;
  16. private Armor _equippedArmor;
  17. private List<Item> _inventory = new List<Item>();
  18. // Temporary stat bonuses (key = source name, value = bonus amount)
  19. private Dictionary<string, float> _attackBonuses = new Dictionary<string, float>();
  20. private Dictionary<string, float> _defenseBonuses = new Dictionary<string, float>();
  21. private Dictionary<string, float> _magicBonuses = new Dictionary<string, float>();
  22. private Dictionary<string, float> _speedBonuses = new Dictionary<string, float>();
  23. private Dictionary<string, float> _healthBonuses = new Dictionary<string, float>();
  24. public string Name { get => name; set => name = value; }
  25. public CharacterStats Stats => _baseStats;
  26. public Weapon EquippedWeapon => _equippedWeapon;
  27. public Armor EquippedArmor => _equippedArmor;
  28. public IReadOnlyList<Item> Inventory => _inventory.AsReadOnly();
  29. public CharacterSheet(GameObject go, CharacterStats baseStats)
  30. {
  31. _baseStats = baseStats;
  32. if (go != null && go.tag.Equals("Agent"))
  33. {
  34. Name = NameGenerator.GenerateRandomName();
  35. }
  36. else if (go != null)
  37. {
  38. Name = go.name;
  39. }
  40. else
  41. {
  42. // Fallback for ScriptableObjects (like Monster templates) that don't have GameObjects
  43. Name = "Unknown";
  44. }
  45. }
  46. /// <summary>
  47. /// Get the effective attack stat including all bonuses.
  48. /// This is what's actually used in combat calculations.
  49. /// </summary>
  50. public float GetEffectiveAttack()
  51. {
  52. float bonus = 0;
  53. foreach (var b in _attackBonuses.Values) bonus += b;
  54. return _baseStats.Attack + bonus;
  55. }
  56. /// <summary>Get effective defense after all bonuses.</summary>
  57. public float GetEffectiveDefense()
  58. {
  59. float bonus = 0;
  60. foreach (var b in _defenseBonuses.Values) bonus += b;
  61. return _baseStats.Defense + bonus;
  62. }
  63. /// <summary>Get effective magic after all bonuses.</summary>
  64. public float GetEffectiveMagic()
  65. {
  66. float bonus = 0;
  67. foreach (var b in _magicBonuses.Values) bonus += b;
  68. return _baseStats.Magic + bonus;
  69. }
  70. /// <summary>Get effective speed (affects initiative and movement).</summary>
  71. public float GetEffectiveSpeed()
  72. {
  73. float bonus = 0;
  74. foreach (var b in _speedBonuses.Values) bonus += b;
  75. return Mathf.Max(0.1f, _baseStats.Speed + bonus);
  76. }
  77. /// <summary>Get effective max health including armor bonuses.</summary>
  78. public float GetEffectiveMaxHealth()
  79. {
  80. float bonus = 0;
  81. foreach (var b in _healthBonuses.Values) bonus += b;
  82. return _baseStats.MaxHealth + bonus;
  83. }
  84. /// <summary>Equip a weapon (unequips the previous one).</summary>
  85. public bool EquipWeapon(Weapon weapon)
  86. {
  87. if (_equippedWeapon != null)
  88. _equippedWeapon.OnUnequip(this);
  89. if (weapon != null && !weapon.OnEquip(this))
  90. return false;
  91. _equippedWeapon = weapon;
  92. return true;
  93. }
  94. /// <summary>Equip armor (unequips the previous armor).</summary>
  95. public bool EquipArmor(Armor armor)
  96. {
  97. if (_equippedArmor != null)
  98. _equippedArmor.OnUnequip(this);
  99. if (armor != null && !armor.OnEquip(this))
  100. return false;
  101. _equippedArmor = armor;
  102. return true;
  103. }
  104. /// <summary>Add an item to inventory without equipping it.</summary>
  105. public void AddToInventory(Item item)
  106. {
  107. if (item != null && !_inventory.Contains(item))
  108. _inventory.Add(item);
  109. }
  110. // Needs a better way to handle this, but for now just remove the first item that matches the name. Returns null if not found.
  111. public Consumable GetHealthPotionFromInventory()
  112. {
  113. List<Consumable> consumables = _inventory.FindAll(i => i is Consumable && ((Consumable)i).HealthBonus > 0).Cast<Consumable>().ToList();
  114. Consumable consumable = consumables.Find(c => c.HealthBonus > 0);
  115. if (consumable != null)
  116. {
  117. _inventory.Remove(consumable);
  118. return consumable;
  119. }
  120. return null;
  121. }
  122. /// <summary>Apply a temporary stat bonus (e.g., from a weapon, buff, or potion).</summary>
  123. public void ApplyTemporaryBonus(string key, float attackBonus = 0, float defenseBonus = 0, float magicBonus = 0, float speedBonus = 0, float healthBonus = 0)
  124. {
  125. if (attackBonus != 0)
  126. _attackBonuses[key] = attackBonus;
  127. if (defenseBonus != 0)
  128. _defenseBonuses[key] = defenseBonus;
  129. if (magicBonus != 0)
  130. _magicBonuses[key] = magicBonus;
  131. if (speedBonus != 0)
  132. _speedBonuses[key] = speedBonus;
  133. if (healthBonus != 0)
  134. _healthBonuses[key] = healthBonus;
  135. }
  136. /// <summary>Overload for single-stat bonus (most common case).</summary>
  137. public void ApplyTemporaryBonus(string key, float bonus, string statType = "attack")
  138. {
  139. switch (statType.ToLower())
  140. {
  141. case "attack": _attackBonuses[key] = bonus; break;
  142. case "defense": _defenseBonuses[key] = bonus; break;
  143. case "magic": _magicBonuses[key] = bonus; break;
  144. case "speed": _speedBonuses[key] = bonus; break;
  145. case "health": _healthBonuses[key] = bonus; break;
  146. }
  147. }
  148. /// <summary>Remove a temporary bonus by its source key.</summary>
  149. public void RemoveTemporaryBonus(string key)
  150. {
  151. _attackBonuses.Remove(key);
  152. _defenseBonuses.Remove(key);
  153. _magicBonuses.Remove(key);
  154. _speedBonuses.Remove(key);
  155. _healthBonuses.Remove(key);
  156. }
  157. /// <summary>Reset this character for a new fight (restore health, clear temporary bonuses, keep equipment).</summary>
  158. public void ResetForNewFight()
  159. {
  160. _baseStats.RestoreHealth();
  161. _attackBonuses.Clear();
  162. _defenseBonuses.Clear();
  163. _magicBonuses.Clear();
  164. _speedBonuses.Clear();
  165. _healthBonuses.Clear();
  166. // Re-apply equipment bonuses
  167. if (_equippedWeapon != null)
  168. _equippedWeapon.OnEquip(this);
  169. if (_equippedArmor != null)
  170. _equippedArmor.OnEquip(this);
  171. }
  172. }
  173. }