using System.Collections.Generic; using System.Linq; using UnityEngine; namespace MazeGen { /// /// Represents a character's complete combat state: base stats, equipped items, /// temporary bonuses, and inventory. Both agents and monsters use this. /// public class CharacterSheet { private string name; private string gameobjectName; private CharacterStats _baseStats; private Weapon _equippedWeapon; private Armor _equippedArmor; private List _inventory = new List(); // Temporary stat bonuses (key = source name, value = bonus amount) private Dictionary _attackBonuses = new Dictionary(); private Dictionary _defenseBonuses = new Dictionary(); private Dictionary _magicBonuses = new Dictionary(); private Dictionary _speedBonuses = new Dictionary(); private Dictionary _healthBonuses = new Dictionary(); public string Name { get => name; set => name = value; } public CharacterStats Stats => _baseStats; public Weapon EquippedWeapon => _equippedWeapon; public Armor EquippedArmor => _equippedArmor; public IReadOnlyList Inventory => _inventory.AsReadOnly(); public CharacterSheet(GameObject go, CharacterStats baseStats) { _baseStats = baseStats; if (go != null && go.tag.Equals("Agent")) { Name = NameGenerator.GenerateRandomName(); } else if (go != null) { Name = go.name; } else { // Fallback for ScriptableObjects (like Monster templates) that don't have GameObjects Name = "Unknown"; } } /// /// Get the effective attack stat including all bonuses. /// This is what's actually used in combat calculations. /// public float GetEffectiveAttack() { float bonus = 0; foreach (var b in _attackBonuses.Values) bonus += b; return _baseStats.Attack + bonus; } /// Get effective defense after all bonuses. public float GetEffectiveDefense() { float bonus = 0; foreach (var b in _defenseBonuses.Values) bonus += b; return _baseStats.Defense + bonus; } /// Get effective magic after all bonuses. public float GetEffectiveMagic() { float bonus = 0; foreach (var b in _magicBonuses.Values) bonus += b; return _baseStats.Magic + bonus; } /// Get effective speed (affects initiative and movement). public float GetEffectiveSpeed() { float bonus = 0; foreach (var b in _speedBonuses.Values) bonus += b; return Mathf.Max(0.1f, _baseStats.Speed + bonus); } /// Get effective max health including armor bonuses. public float GetEffectiveMaxHealth() { float bonus = 0; foreach (var b in _healthBonuses.Values) bonus += b; return _baseStats.MaxHealth + bonus; } /// Equip a weapon (unequips the previous one). public bool EquipWeapon(Weapon weapon) { if (_equippedWeapon != null) _equippedWeapon.OnUnequip(this); if (weapon != null && !weapon.OnEquip(this)) return false; _equippedWeapon = weapon; return true; } /// Equip armor (unequips the previous armor). public bool EquipArmor(Armor armor) { if (_equippedArmor != null) _equippedArmor.OnUnequip(this); if (armor != null && !armor.OnEquip(this)) return false; _equippedArmor = armor; return true; } /// Add an item to inventory without equipping it. public void AddToInventory(Item item) { if (item != null && !_inventory.Contains(item)) _inventory.Add(item); } // Needs a better way to handle this, but for now just remove the first item that matches the name. Returns null if not found. public Consumable GetHealthPotionFromInventory() { List consumables = _inventory.FindAll(i => i is Consumable && ((Consumable)i).HealthBonus > 0).Cast().ToList(); Consumable consumable = consumables.Find(c => c.HealthBonus > 0); if (consumable != null) { _inventory.Remove(consumable); return consumable; } return null; } /// Apply a temporary stat bonus (e.g., from a weapon, buff, or potion). public void ApplyTemporaryBonus(string key, float attackBonus = 0, float defenseBonus = 0, float magicBonus = 0, float speedBonus = 0, float healthBonus = 0) { if (attackBonus != 0) _attackBonuses[key] = attackBonus; if (defenseBonus != 0) _defenseBonuses[key] = defenseBonus; if (magicBonus != 0) _magicBonuses[key] = magicBonus; if (speedBonus != 0) _speedBonuses[key] = speedBonus; if (healthBonus != 0) _healthBonuses[key] = healthBonus; } /// Overload for single-stat bonus (most common case). public void ApplyTemporaryBonus(string key, float bonus, string statType = "attack") { switch (statType.ToLower()) { case "attack": _attackBonuses[key] = bonus; break; case "defense": _defenseBonuses[key] = bonus; break; case "magic": _magicBonuses[key] = bonus; break; case "speed": _speedBonuses[key] = bonus; break; case "health": _healthBonuses[key] = bonus; break; } } /// Remove a temporary bonus by its source key. public void RemoveTemporaryBonus(string key) { _attackBonuses.Remove(key); _defenseBonuses.Remove(key); _magicBonuses.Remove(key); _speedBonuses.Remove(key); _healthBonuses.Remove(key); } /// Reset this character for a new fight (restore health, clear temporary bonuses, keep equipment). public void ResetForNewFight() { _baseStats.RestoreHealth(); _attackBonuses.Clear(); _defenseBonuses.Clear(); _magicBonuses.Clear(); _speedBonuses.Clear(); _healthBonuses.Clear(); // Re-apply equipment bonuses if (_equippedWeapon != null) _equippedWeapon.OnEquip(this); if (_equippedArmor != null) _equippedArmor.OnEquip(this); } } }