protected void UpdateTypeParameters(EnemyData data, IEnumerable <GroupType> tags)
    {
        StatBonus critBonus       = data.GetMultiStatBonus(abilityBonuses, tags, BonusType.GLOBAL_CRITICAL_CHANCE);
        StatBonus critDamageBonus = data.GetMultiStatBonus(abilityBonuses, tags, BonusType.GLOBAL_CRITICAL_DAMAGE);

        if (abilityBase.abilityType == AbilityType.SPELL)
        {
            StatBonus speedBonus = data.GetMultiStatBonus(abilityBonuses, tags, BonusType.CAST_SPEED, BonusType.GLOBAL_ABILITY_SPEED);
            StatBonus rangeBonus = data.GetMultiStatBonus(abilityBonuses, tags, BonusType.SPELL_RANGE);

            MainCriticalChance = critBonus.CalculateStat(abilityBase.baseCritical);
            Cooldown           = 1f / speedBonus.CalculateStat(abilityBase.attacksPerSec);
            TargetRange        = rangeBonus.CalculateStat(abilityBase.targetRange);
        }
        else if (abilityBase.abilityType == AbilityType.ATTACK)
        {
            StatBonus speedBonus = data.GetMultiStatBonus(abilityBonuses, tags, BonusType.GLOBAL_ATTACK_SPEED, BonusType.GLOBAL_ABILITY_SPEED);
            StatBonus rangeBonus = new StatBonus();
            if (abilityBase.GetGroupTypes().Contains(GroupType.MELEE_ATTACK))
            {
                data.GetMultiStatBonus(rangeBonus, abilityBonuses, tags, BonusType.MELEE_ATTACK_RANGE);
            }
            if (abilityBase.GetGroupTypes().Contains(GroupType.RANGED_ATTACK))
            {
                data.GetMultiStatBonus(rangeBonus, abilityBonuses, tags, BonusType.RANGED_ATTACK_RANGE);
            }

            MainCriticalChance = critBonus.CalculateStat(data.BaseEnemyData.attackCriticalChance);
            Cooldown           = 1 / speedBonus.CalculateStat(data.BaseEnemyData.attackSpeed);
            TargetRange        = rangeBonus.CalculateStat(data.BaseEnemyData.attackTargetRange);
        }
        MainCriticalDamage = 1f + (critDamageBonus.CalculateStat(50) / 100f);

        if (float.IsInfinity(Cooldown))
        {
            Cooldown = 0.001f;
        }
    }
    protected void UpdateDamage(EnemyData data, Dictionary <ElementType, AbilityDamageBase> damageLevels, IEnumerable <GroupType> tags, float damageModifier = 1.0f)
    {
        if (abilityBase.abilityType == AbilityType.AURA || abilityBase.abilityType == AbilityType.SELF_BUFF)
        {
            return;
        }

        int[] mainConvertedDamageMin = new int[7];
        int[] mainConvertedDamageMax = new int[7];

        float       flatDamageMod = abilityBase.flatDamageMultiplier;
        AbilityType abilityType   = abilityBase.abilityType;

        foreach (ElementType element in Enum.GetValues(typeof(ElementType)))
        {
            mainDamageBase[element].baseMin = 0;
            mainDamageBase[element].baseMax = 0;
            MinMaxRange abilityBaseDamage;

            if (damageLevels.ContainsKey(element))
            {
                abilityBaseDamage = damageLevels[element].damage[abilityLevel];
            }
            else
            {
                abilityBaseDamage = new MinMaxRange();
            }

            if (abilityBase.abilityType == AbilityType.ATTACK && element == ElementType.PHYSICAL)
            {
                flatDamageMod = abilityBase.weaponMultiplier + abilityBase.weaponMultiplierScaling * 50;
                mainDamageBase[element].baseMin = (abilityBaseDamage.min + data.minAttackDamage) * flatDamageMod;
                mainDamageBase[element].baseMax = (abilityBaseDamage.max + data.maxAttackDamage) * flatDamageMod;
            }
            else
            {
                mainDamageBase[element].baseMin = abilityBaseDamage.min;
                mainDamageBase[element].baseMax = abilityBaseDamage.max;
            }

            IList <GroupType>   damageTags   = abilityBase.GetGroupTypes();
            HashSet <GroupType> mainHandTags = AbilityOwner.GetActorTagsAndDataTags();

            HashSet <BonusType> min   = new HashSet <BonusType>();
            HashSet <BonusType> max   = new HashSet <BonusType>();
            HashSet <BonusType> multi = new HashSet <BonusType>();

            Helpers.GetGlobalAndFlatDamageTypes(element, abilityBase.abilityType, abilityBase.abilityShotType, damageTags, min, max, multi);
            multi.UnionWith(Helpers.GetMultiplierTypes(abilityBase.abilityType, element));

            mainDamageBase[element].ClearBonuses();

            data.GetMultiStatBonus(mainDamageBase[element].minBonus, abilityBonuses, mainHandTags, min.ToArray());
            data.GetMultiStatBonus(mainDamageBase[element].maxBonus, abilityBonuses, mainHandTags, max.ToArray());
            data.GetMultiStatBonus(mainDamageBase[element].multiplierBonus, abilityBonuses, mainHandTags, multi.ToArray());

            mainDamageBase[element].CalculateRange(flatDamageMod, finalDamageModifier);

            //Debug.Log(mainDamageBase[element].calculatedRange.min + " " + mainDamageBase[element].calculatedRange.max + " " + element);
        }
    }