using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using UnityEngine.Events; public enum CharacterStatType { Cunning, Flow, Presence, AttackDamage, SpellDamage, AttackSpeed, CritChance, CritDamage, AuraPower, MaxHealth, HealthRegen, MaxMana, ManaRegen, Armor, MagicResistance, DodgeChance, BlockChance, BlockEffectiveness, AreaEffectiveness, CooldownReduction, MovementSpeed, ReputationGainIncrease, GoldCostReduction } public static class CharacterStatHelper { public static List Attributes = new List() { CharacterStatType.Cunning, CharacterStatType.Flow, CharacterStatType.Presence }; public static bool IsAttribute(CharacterStatType type) { return Attributes.Contains(type); } public static List Damage = new List() { CharacterStatType.AttackDamage, CharacterStatType.SpellDamage, }; public static bool IsDamage(CharacterStatType type) { return Damage.Contains(type); } public static List Offensive = new List() { CharacterStatType.AttackSpeed, CharacterStatType.CritChance, CharacterStatType.CritDamage, //CharacterStatType.AuraPower, }; public static bool IsOffensive(CharacterStatType type) { return Offensive.Contains(type); } public static List Defensive = new List() { CharacterStatType.Armor, CharacterStatType.MagicResistance, CharacterStatType.DodgeChance, CharacterStatType.BlockChance, CharacterStatType.BlockEffectiveness, }; public static bool IsDefensive(CharacterStatType type) { return Defensive.Contains(type); } public static List Resource = new List() { CharacterStatType.MaxHealth, CharacterStatType.HealthRegen, CharacterStatType.MaxMana, CharacterStatType.ManaRegen, }; public static bool IsResource(CharacterStatType type) { return Resource.Contains(type); } public static List Control = new List() { CharacterStatType.AreaEffectiveness, CharacterStatType.CooldownReduction, CharacterStatType.MovementSpeed, }; public static bool IsControl(CharacterStatType type) { return Control.Contains(type); } public static List Misc = new List() { CharacterStatType.ReputationGainIncrease, CharacterStatType.GoldCostReduction, }; public static bool IsMisc(CharacterStatType type) { return Misc.Contains(type); } } namespace Kryz.CharacterStats { [Serializable] public class CharacterStat { public GameTag statTag; public StatDefinition statDefinition; public float BaseValue; protected bool isDirty = true; protected float lastBaseValue; protected float _value; public virtual float Value { get { if (isDirty || lastBaseValue != BaseValue) { lastBaseValue = BaseValue; _value = CalculateFinalValue(); isDirty = false; } return _value; } } protected readonly List statModifiers; public readonly ReadOnlyCollection StatModifiers; public CharacterStat() { statModifiers = new List(); StatModifiers = statModifiers.AsReadOnly(); } public CharacterStat(float baseValue) : this() { isDirty = true; BaseValue = baseValue; } public virtual void AddModifier(StatModifier mod) { isDirty = true; statModifiers.Add(mod); } public virtual bool RemoveModifier(StatModifier mod) { if (statModifiers.Remove(mod)) { isDirty = true; return true; } return false; } public virtual bool HasModifiersFromSource(object source) { return StatModifiers.Any(mod => mod.Source == source); } public virtual bool RemoveAllModifiersFromSource(object source) { int numRemovals = statModifiers.RemoveAll(mod => mod.Source == source); if (numRemovals > 0) { isDirty = true; return true; } return false; } protected virtual int CompareModifierOrder(StatModifier a, StatModifier b) { if (a.Order < b.Order) return -1; else if (a.Order > b.Order) return 1; return 0; //if (a.Order == b.Order) } protected virtual float CalculateFinalValue() { float finalValue = BaseValue; float sumPercentAdd = 0; statModifiers.Sort(CompareModifierOrder); for (int i = 0; i < statModifiers.Count; i++) { StatModifier mod = statModifiers[i]; if (mod.Type == StatModType.Flat) { finalValue += mod.Value; } else if (mod.Type == StatModType.PercentAdd) { sumPercentAdd += mod.Value; if (i + 1 >= statModifiers.Count || statModifiers[i + 1].Type != StatModType.PercentAdd) { finalValue *= 1 + sumPercentAdd; sumPercentAdd = 0; } } else if (mod.Type == StatModType.PercentMult) { finalValue *= 1 + mod.Value; } } // Workaround for float calculation errors, like displaying 12.00001 instead of 12 return (float)Math.Round(finalValue, 4); } } }