using Kryz.CharacterStats; using Kryz.CharacterStats.Examples; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; [System.Serializable] public class EquippableItemInstance : ItemInstance { public int AttackDamageBonus; public int SpellDamageBonus; //no flat attack speed bonus, only % public int CritChanceBonus; public int CritDamageBonus; public int MaxHealthBonus; public int HealthRegenBonus; public int MaxManaBonus; public int ManaRegenBonus; public int ArmorBonus; public int MagicResistanceBonus; //no flat dodge //no flat block chance //no flat block effectiveness //no flat area //no flat cdr //no flat movespeed //no flat rep gains //no flat gold cost reduction [Space] public float AttackDamagePercentBonus; public float SpellDamagePercentBonus; public float AttackSpeedPercentBonus; public float CritChancePercentBonus; public float CritDamagePercentBonus; public float MaxHealthPercentBonus; public float HealthRegenPercentBonus; public float MaxManaPercentBonus; public float ManaRegenPercentBonus; public float ArmorPercentBonus; public float MagicResistancePercentBonus; public float DodgeChancePercentBonus; public float BlockChancePercentBonus; public float BlockEffectivenessPercentBonus; public float AreaEffectivenessPercentBonus; public float CooldownReductionPercentBonus; public float MovementSpeedPercentBonus; public float ReputationGainIncreasePercentBonus; public float GoldCostReductionPercentBonus; [Space] public EquipmentType EquipmentType; [Space] public bool CraftableBase = false; [Space] /// /// Can only contain up to this number of unique stats in a single item instance. /// [Space] [Tooltip("Can only contain up to this number of unique stats in a single item instance.")] public int MaxTotalUniqueStatsIncreasedByStones; public List AddedStoneStats = new List(); public void Equip(PlayerCharacterStats c) { if (AttackDamageBonus != 0) c.AttackDamage.AddModifier(new StatModifier(AttackDamageBonus, StatModType.Flat, this)); if (SpellDamageBonus != 0) c.SpellDamage.AddModifier(new StatModifier(SpellDamageBonus, StatModType.Flat, this)); if (CritChanceBonus != 0) c.CritChance.AddModifier(new StatModifier(CritChanceBonus, StatModType.Flat, this)); if (CritDamageBonus != 0) c.CritDamage.AddModifier(new StatModifier(CritDamageBonus, StatModType.Flat, this)); if (MaxHealthBonus != 0) c.MaxHealth.AddModifier(new StatModifier(MaxHealthBonus, StatModType.Flat, this)); if (HealthRegenBonus != 0) c.HealthRegen.AddModifier(new StatModifier(HealthRegenBonus, StatModType.Flat, this)); if (MaxManaBonus != 0) c.MaxMana.AddModifier(new StatModifier(MaxManaBonus, StatModType.Flat, this)); if (ManaRegenBonus != 0) c.ManaRegen.AddModifier(new StatModifier(ManaRegenBonus, StatModType.Flat, this)); if (ArmorBonus != 0) c.Armor.AddModifier(new StatModifier(ArmorBonus, StatModType.Flat, this)); if (MagicResistanceBonus != 0) c.MagicResistance.AddModifier(new StatModifier(MagicResistanceBonus, StatModType.Flat, this)); if (AttackDamagePercentBonus != 0) c.AttackDamage.AddModifier(new StatModifier(AttackDamagePercentBonus, StatModType.PercentAdd, this)); if (SpellDamagePercentBonus != 0) c.SpellDamage.AddModifier(new StatModifier(SpellDamagePercentBonus, StatModType.PercentAdd, this)); if (AttackSpeedPercentBonus != 0) c.AttackSpeed.AddModifier(new StatModifier(AttackSpeedPercentBonus, StatModType.PercentAdd, this)); if (CritChancePercentBonus != 0) c.CritChance.AddModifier(new StatModifier(CritChancePercentBonus, StatModType.PercentAdd, this)); if (CritDamagePercentBonus != 0) c.CritDamage.AddModifier(new StatModifier(CritDamagePercentBonus, StatModType.PercentAdd, this)); if (MaxHealthPercentBonus != 0) c.MaxHealth.AddModifier(new StatModifier(MaxHealthPercentBonus, StatModType.PercentAdd, this)); if (HealthRegenPercentBonus != 0) c.HealthRegen.AddModifier(new StatModifier(HealthRegenPercentBonus, StatModType.PercentAdd, this)); if (MaxManaPercentBonus != 0) c.MaxMana.AddModifier(new StatModifier(MaxManaPercentBonus, StatModType.PercentAdd, this)); if (ManaRegenPercentBonus != 0) c.ManaRegen.AddModifier(new StatModifier(ManaRegenPercentBonus, StatModType.PercentAdd, this)); if (ArmorPercentBonus != 0) c.Armor.AddModifier(new StatModifier(ArmorPercentBonus, StatModType.PercentAdd, this)); if (MagicResistancePercentBonus != 0) c.MagicResistance.AddModifier(new StatModifier(MagicResistancePercentBonus, StatModType.PercentAdd, this)); if (DodgeChancePercentBonus != 0) c.DodgeChance.AddModifier(new StatModifier(DodgeChancePercentBonus, StatModType.PercentAdd, this)); if (BlockChancePercentBonus != 0) c.BlockChance.AddModifier(new StatModifier(BlockChancePercentBonus, StatModType.PercentAdd, this)); if (BlockEffectivenessPercentBonus != 0) c.BlockEffectiveness.AddModifier(new StatModifier(BlockEffectivenessPercentBonus, StatModType.PercentAdd, this)); if (AreaEffectivenessPercentBonus != 0) c.AreaEffectiveness.AddModifier(new StatModifier(AreaEffectivenessPercentBonus, StatModType.PercentAdd, this)); if (CooldownReductionPercentBonus != 0) c.CooldownReduction.AddModifier(new StatModifier(CooldownReductionPercentBonus, StatModType.PercentAdd, this)); if (MovementSpeedPercentBonus != 0) c.MovementSpeed.AddModifier(new StatModifier(MovementSpeedPercentBonus, StatModType.PercentAdd, this)); if (ReputationGainIncreasePercentBonus != 0) c.ReputationGainIncrease.AddModifier(new StatModifier(ReputationGainIncreasePercentBonus, StatModType.PercentAdd, this)); if (GoldCostReductionPercentBonus != 0) c.GoldCostReduction.AddModifier(new StatModifier(GoldCostReductionPercentBonus, StatModType.PercentAdd, this)); } public void Unequip(PlayerCharacterStats c) { c.AttackDamage.RemoveAllModifiersFromSource(this); c.SpellDamage.RemoveAllModifiersFromSource(this); c.AttackSpeed.RemoveAllModifiersFromSource(this); c.CritChance.RemoveAllModifiersFromSource(this); c.CritDamage.RemoveAllModifiersFromSource(this); c.MaxHealth.RemoveAllModifiersFromSource(this); c.HealthRegen.RemoveAllModifiersFromSource(this); c.MaxMana.RemoveAllModifiersFromSource(this); c.ManaRegen.RemoveAllModifiersFromSource(this); c.Armor.RemoveAllModifiersFromSource(this); c.MagicResistance.RemoveAllModifiersFromSource(this); c.DodgeChance.RemoveAllModifiersFromSource(this); c.BlockChance.RemoveAllModifiersFromSource(this); c.BlockEffectiveness.RemoveAllModifiersFromSource(this); c.AreaEffectiveness.RemoveAllModifiersFromSource(this); c.CooldownReduction.RemoveAllModifiersFromSource(this); c.MovementSpeed.RemoveAllModifiersFromSource(this); c.ReputationGainIncrease.RemoveAllModifiersFromSource(this); c.GoldCostReduction.RemoveAllModifiersFromSource(this); } public bool CanAddCraftingStone(CraftingStatStone stone) { if (!CraftableBase) return false; var stoneStats = GetNonZeroStats(stone); var itemNonZeroStats = GetNonZeroStats(this); int newUniqueStats = stoneStats.Except(itemNonZeroStats).Count(); // Ensure we don't exceed the max unique stats cap if (AddedStoneStats.Count + newUniqueStats > MaxTotalUniqueStatsIncreasedByStones) { return false; // Adding the crafting stone would exceed the cap } return true; } public bool TryAddCraftingStone(CraftingStatStone stone) { if (!CanAddCraftingStone(stone)) return false; var stoneStats = GetNonZeroStats(stone); var itemStats = GetNonZeroStats(this); for (int i = 0; i < stoneStats.Count; i++) { if (!itemStats.Contains(stoneStats[i]) && !AddedStoneStats.Contains(stoneStats[i])) AddedStoneStats.Add(stoneStats[i]); } // Add stats from the stone to the item AddStats(stone); return true; } private List GetNonZeroStats(object stats) { var nonZeroStats = new List(); var fields = stats.GetType().GetFields(); foreach (var field in fields) { if (field.GetValue(stats) is int intValue && intValue != 0 && field.Name.ToLower().Contains("bonus")) { nonZeroStats.Add(field.Name); } else if (field.GetValue(stats) is float floatValue && !Mathf.Approximately(floatValue, 0f) && field.Name.ToLower().Contains("bonus")) { nonZeroStats.Add(field.Name); } } return nonZeroStats; } //TODO: Add new stats to stones too private void AddStats(CraftingStatStone stone) { AttackDamageBonus += stone.AttackDamageBonus; SpellDamageBonus += stone.SpellDamageBonus; CritChanceBonus += stone.CritChanceBonus; CritDamageBonus += stone.CritDamageBonus; MaxHealthBonus += stone.MaxHealthBonus; ArmorBonus += stone.ArmorBonus; MagicResistanceBonus += stone.MagicResistanceBonus; AttackDamagePercentBonus += stone.AttackDamagePercentBonus; SpellDamagePercentBonus += stone.SpellDamagePercentBonus; CritChancePercentBonus += stone.CritChancePercentBonus; CritDamagePercentBonus += stone.CritDamagePercentBonus; MaxHealthPercentBonus += stone.MaxHealthPercentBonus; ArmorPercentBonus += stone.ArmorPercentBonus; MagicResistancePercentBonus += stone.MagicResistancePercentBonus; } //TODO: Add new stats public EquippableItemInstance() { AttackDamageBonus = 0; SpellDamageBonus = 0; CritChanceBonus = 0; CritDamageBonus = 0; MaxHealthBonus = 0; ArmorBonus = 0; MagicResistanceBonus = 0; AttackDamagePercentBonus = 0; SpellDamagePercentBonus = 0; CritChancePercentBonus = 0; CritDamagePercentBonus = 0; MaxHealthPercentBonus = 0; ArmorPercentBonus = 0; MagicResistancePercentBonus = 0; EquipmentType = EquipmentType.Helmet; CraftableBase = false; MaxTotalUniqueStatsIncreasedByStones = 0; } public EquippableItemInstance(EquippableItem template) { ItemName = template.ItemName; Icon = template.Icon; sellPricePlayer = template.sellPricePlayer; sellPriceVendor = template.sellPriceVendor; description = template.description; templateIndex = ItemIndexer.Instance.Items.IndexOf(template); AttackDamageBonus = template.AttackDamageBonus; SpellDamageBonus = template.SpellDamageBonus; CritChanceBonus = template.CritChanceBonus; CritDamageBonus = template.CritDamageBonus; MaxHealthBonus = template.MaxHealthBonus; ArmorBonus = template.ArmorBonus; MagicResistanceBonus = template.MagicResistanceBonus; AttackDamagePercentBonus = template.AttackDamagePercentBonus; SpellDamagePercentBonus = template.SpellDamagePercentBonus; CritChancePercentBonus = template.CritChancePercentBonus; CritDamagePercentBonus = template.CritDamagePercentBonus; MaxHealthPercentBonus = template.MaxHealthPercentBonus; ArmorPercentBonus = template.ArmorPercentBonus; MagicResistancePercentBonus = template.MagicResistancePercentBonus; EquipmentType = template.EquipmentType; CraftableBase = template.CraftableBase; MaxTotalUniqueStatsIncreasedByStones = template.MaxTotalUniqueStatsIncreasedByStones; } public EquippableItemInstance(EquippableItem template, bool randomizeStats) { ItemName = template.ItemName; Icon = template.Icon; sellPricePlayer = template.sellPricePlayer; sellPriceVendor = template.sellPriceVendor; description = template.description; templateIndex = ItemIndexer.Instance.Items.IndexOf(template); if (randomizeStats) { AttackDamageBonus = Random.Range(template.MinAttackDamageBonus, template.MaxAttackDamageBonus); SpellDamageBonus = Random.Range(template.MinSpellDamageBonus, template.MaxSpellDamageBonus); CritChanceBonus = Random.Range(template.MinCritChanceBonus, template.MaxCritChanceBonus); CritDamageBonus = Random.Range(template.MinCritDamageBonus, template.MaxCritDamageBonus); MaxHealthBonus = Random.Range(template.MinMaxHealthBonus, template.MaxMaxHealthBonus); ArmorBonus = Random.Range(template.MinArmorBonus, template.MaxArmorBonus); MagicResistanceBonus = Random.Range(template.MinMagicResistanceBonus, template.MaxMagicResistanceBonus); AttackDamagePercentBonus = Mathf.Round(Random.Range(template.MinAttackDamagePercentBonus, template.MaxAttackDamagePercentBonus) * 100f) / 100f; SpellDamagePercentBonus = Mathf.Round(Random.Range(template.MinSpellDamagePercentBonus, template.MaxSpellDamagePercentBonus) * 100f) / 100f; CritChancePercentBonus = Mathf.Round(Random.Range(template.MinCritChancePercentBonus, template.MaxCritChancePercentBonus) * 100f) / 100f; CritDamagePercentBonus = Mathf.Round(Random.Range(template.MinCritDamagePercentBonus, template.MaxCritDamagePercentBonus) * 100f) / 100f; MaxHealthPercentBonus = Mathf.Round(Random.Range(template.MinMaxHealthPercentBonus, template.MaxMaxHealthPercentBonus) * 100f) / 100f; ArmorPercentBonus = Mathf.Round(Random.Range(template.MinArmorPercentBonus, template.MaxArmorPercentBonus) * 100f) / 100f; MagicResistancePercentBonus = Mathf.Round(Random.Range(template.MinMagicResistancePercentBonus, template.MaxMagicResistancePercentBonus) * 100f) / 100f; } else { AttackDamageBonus = template.AttackDamageBonus; SpellDamageBonus = template.SpellDamageBonus; CritChanceBonus = template.CritChanceBonus; CritDamageBonus = template.CritDamageBonus; MaxHealthBonus = template.MaxHealthBonus; ArmorBonus = template.ArmorBonus; MagicResistanceBonus = template.MagicResistanceBonus; AttackDamagePercentBonus = template.AttackDamagePercentBonus; SpellDamagePercentBonus = template.SpellDamagePercentBonus; CritChancePercentBonus = template.CritChancePercentBonus; CritDamagePercentBonus = template.CritDamagePercentBonus; MaxHealthPercentBonus = template.MaxHealthPercentBonus; ArmorPercentBonus = template.ArmorPercentBonus; MagicResistancePercentBonus = template.MagicResistancePercentBonus; } EquipmentType = template.EquipmentType; CraftableBase = template.CraftableBase; MaxTotalUniqueStatsIncreasedByStones = template.MaxTotalUniqueStatsIncreasedByStones; } }