using Kryz.CharacterStats; using Kryz.CharacterStats.Examples; using System.Collections.Generic; using System.Linq; using UnityEngine; [System.Serializable] public class ItemStatBonus { public StatDefinition statDefinition; public string statKey = ""; public float flatValue; public float percentValue; public bool HasFlatBonus => flatValue != 0; public bool HasPercentBonus => percentValue != 0; public bool HasAnyBonus => HasFlatBonus || HasPercentBonus; public ItemStatBonus() { } public ItemStatBonus(StatDefinition stat, float flat = 0f, float percent = 0f) { statDefinition = stat; flatValue = flat; percentValue = percent; statKey = stat.StatKey; } } [System.Serializable] public class EquippableItemInstance : ItemInstance { [Header("Equipment Identity")] public EquipmentType EquipmentType; public WeaponType WeaponType; [Header("Dynamic Stat System")] public List statBonuses = new List(); [Header("Crafting System")] public bool CraftableBase = false; public int MaxTotalUniqueStatsIncreasedByStones; public List AddedStoneStats = new List(); // Helper properties public bool IsWeapon => EquipmentType == EquipmentType.Weapon1 || EquipmentType == EquipmentType.Weapon2; public bool IsTwoHandedWeapon => IsWeapon && WeaponType.IsTwoHanded(); public bool IsOneHandedWeapon => IsWeapon && WeaponType.IsOneHanded(); public void Equip(PlayerCharacterStats characterStats) { foreach (var bonus in statBonuses) { if (bonus.statDefinition == null || !bonus.HasAnyBonus) continue; var stat = characterStats.GetStat(bonus.statDefinition.StatKey); if (stat != null) { // Apply flat bonus if (bonus.HasFlatBonus) { stat.AddModifier(new StatModifier(bonus.flatValue, StatModType.Flat, this)); } // Apply percent bonus if (bonus.HasPercentBonus) { stat.AddModifier(new StatModifier(bonus.percentValue, StatModType.PercentAdd, this)); } } else { Debug.LogWarning($"EquippableItemInstance: Stat '{bonus.statDefinition.StatKey}' not found in character stats!"); } } } public void Unequip(PlayerCharacterStats characterStats) { // Remove all modifiers from this item source across all stats var allStats = characterStats.GetAllStats(); foreach (var kvp in allStats) { kvp.RemoveAllModifiersFromSource(this); } } // Stat management methods public void AddStatBonus(StatDefinition statDef, float flatValue = 0f, float percentValue = 0f) { var existingBonus = statBonuses.FirstOrDefault(b => b.statDefinition == statDef); if (existingBonus != null) { existingBonus.flatValue += flatValue; existingBonus.percentValue += percentValue; } else { statBonuses.Add(new ItemStatBonus(statDef, flatValue, percentValue)); } } public void SetStatBonus(StatDefinition statDef, float flatValue = 0f, float percentValue = 0f) { var existingBonus = statBonuses.FirstOrDefault(b => b.statDefinition == statDef); if (existingBonus != null) { existingBonus.flatValue = flatValue; existingBonus.percentValue = percentValue; } else { statBonuses.Add(new ItemStatBonus(statDef, flatValue, percentValue)); } } public ItemStatBonus GetStatBonus(StatDefinition statDef) { return statBonuses.FirstOrDefault(b => b.statDefinition == statDef); } public bool HasStat(StatDefinition statDef) { var bonus = GetStatBonus(statDef); return bonus != null && bonus.HasAnyBonus; } public List GetAllNonZeroBonuses() { return statBonuses.Where(b => b.HasAnyBonus).ToList(); } public int GetUniqueStatCount() { return GetAllNonZeroBonuses().Count; } // Crafting stone system (updated to use new stat system) public bool CanAddCraftingStone(CraftingStatStone stone) { if (!CraftableBase) return false; var stoneStats = GetNonZeroStatsFromStone(stone); var currentStats = GetAllNonZeroBonuses().Select(b => b.statDefinition.StatKey).ToList(); int newUniqueStats = stoneStats.Except(currentStats).Count(); // Ensure we don't exceed the max unique stats cap if (AddedStoneStats.Count + newUniqueStats > MaxTotalUniqueStatsIncreasedByStones) { return false; } return true; } public bool TryAddCraftingStone(CraftingStatStone stone) { if (!CanAddCraftingStone(stone)) return false; var stoneStats = GetNonZeroStatsFromStone(stone); var currentStats = GetAllNonZeroBonuses().Select(b => b.statDefinition.StatKey).ToList(); // Track new stats being added foreach (var statKey in stoneStats) { if (!currentStats.Contains(statKey) && !AddedStoneStats.Contains(statKey)) { AddedStoneStats.Add(statKey); } } // Add stats from the stone to the item (this needs to be updated based on your stone structure) AddStatsFromStone(stone); return true; } private List GetNonZeroStatsFromStone(CraftingStatStone stone) { var nonZeroStats = new List(); var fields = stone.GetType().GetFields(); foreach (var field in fields) { if (field.GetValue(stone) is int intValue && intValue != 0 && field.Name.ToLower().Contains("bonus")) { nonZeroStats.Add(field.Name); } else if (field.GetValue(stone) is float floatValue && !Mathf.Approximately(floatValue, 0f) && field.Name.ToLower().Contains("bonus")) { nonZeroStats.Add(field.Name); } } return nonZeroStats; } // This method needs to be updated based on your CraftingStatStone structure private void AddStatsFromStone(CraftingStatStone stone) { // TODO: Update this to work with the new stat system // You'll need to map stone properties to StatDefinition references // For now, keeping the old structure as a placeholder Debug.LogWarning("AddStatsFromStone needs to be updated for the new stat system"); } // Constructors public EquippableItemInstance() { EquipmentType = EquipmentType.Helmet; WeaponType = WeaponType.Sword; CraftableBase = false; MaxTotalUniqueStatsIncreasedByStones = 0; statBonuses = new List(); AddedStoneStats = new List(); templateIndex = -1; } // Constructor for generating from EquipmentTypeDefinition (recommended approach) public EquippableItemInstance(EquippableItemTypeDefinition equipmentTypeDef, string itemName, Sprite icon, string iconPath = null) { ItemName = itemName; Icon = icon; IconPath = iconPath ?? ""; // Store the icon path EquipmentType = equipmentTypeDef.EquipmentType; WeaponType = equipmentTypeDef.WeaponType; CraftableBase = false; // Set based on your needs MaxTotalUniqueStatsIncreasedByStones = 6; // Default value statBonuses = new List(); AddedStoneStats = new List(); templateIndex = -1; // You can set default sell prices here or pass them as parameters sellPricePlayer = 100; sellPriceVendor = 50; description = $"A {equipmentTypeDef.GetDisplayName()}"; } // Helper method to set icon with path public void SetIcon(Sprite icon, string iconPath) { Icon = icon; IconPath = iconPath; } // Helper method to get icon path from EquipmentTypeDefinition public static string GetIconPathFromEquipmentType(EquippableItemTypeDefinition equipmentTypeDef, Sprite icon) { if (equipmentTypeDef.UseResourcesFolder && !string.IsNullOrEmpty(equipmentTypeDef.ResourcesPath)) { return $"{equipmentTypeDef.ResourcesPath}/{icon.name}"; } return ""; // Manual icons don't have paths } // Utility methods for debugging and UI public string GetStatSummary() { if (statBonuses.Count == 0) return "No stat bonuses"; var summary = new List(); foreach (var bonus in GetAllNonZeroBonuses()) { var parts = new List(); if (bonus.HasFlatBonus) parts.Add($"+{bonus.flatValue:F0}"); if (bonus.HasPercentBonus) parts.Add($"+{bonus.percentValue:P1}"); summary.Add($"{bonus.statDefinition.DisplayName}: {string.Join(" ", parts)}"); } return string.Join("\n", summary); } [ContextMenu("Log Stat Summary")] private void LogStatSummary() { Debug.Log($"=== {ItemName} Stats ===\n{GetStatSummary()}"); } }