Encounter / Assets / Scripts / UtilityHandler.cs
UtilityHandler.cs
Raw
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using UnityEngine;

/// <summary>
/// Handles mostly pure function components that populate parts of the code a lot
/// </summary>
public static class UtilityHandler
{
    /// <summary>
    /// General Dice Rolling Functionality for collections of dice values
    /// </summary>
    /// <param name="diceBundle">The collection of dice to roll</param>
    /// <returns>The total int value created from the rolling of all the dice</returns>
    public static int RollValue(params Dice.DiceR[] diceBundle)
    {
        int output = 0;

        foreach (var d in diceBundle)
        {
            Dice dice = DiceRoller.DispenseDice(d);
            output += DiceRoller.RollDice(dice);
        }

        return output;
    }
    /// <summary>
    /// General Dice Rolling Functionality for collections in inclusion of a base value
    /// </summary>
    /// <param name="value">The base value that will always be the start of the output</param>
    /// <param name="diceBundle">The collection of dices to roll</param>
    /// <returns>The total int value created from the base value and rolling all dice in diceBundle</returns>
    public static int RollValueWithBase(int value, params Dice.DiceR[] diceBundle)
    {
        int output = value;

        foreach (var d in diceBundle)
        {
            Dice dice = DiceRoller.DispenseDice(d);
            output += DiceRoller.RollDice(dice);
        }

        return output;
    }
    public static int Average(int[] damageValues)
    {
        int output = 0;
        foreach (int value in damageValues)
            output += value;

        return output / damageValues.Length;
    }
    public static int SpellTypeCheck(Spell currentSpell, int spellValue, Entity spellTarget, Entity spellUser)
    {
        SpellSO.Element targetType = spellTarget.GetEntityType();
        SpellSO.Element spellType = currentSpell.SpellType;

        spellType = ElementalAugmentationFunction(spellUser, spellType);

        spellValue = DeathAndDecayCheck(currentSpell, spellValue, spellUser, spellType);
        spellValue = ElementWeaknessAndResistChecks(spellValue, spellType, spellTarget, spellUser, currentSpell);
        spellValue = UniqueSpellTypeChecks(currentSpell, spellValue, targetType);

        return spellValue;
    }

    private static int DeathAndDecayCheck(Spell currentSpell, int spellValue, Entity spellUser, SpellSO.Element spellType)
    {
        if (spellUser.GetInventory().Abilities.Contains(AbilityBrain.GetAbilityList()[114]) && spellType is SpellSO.Element.Necro)
        {
            SpellSO.SpellEffect spellEffect = currentSpell.SpellEffects[0];

            bool isDamaging = spellEffect is SpellSO.SpellEffect.Damage;

            if (isDamaging)
                spellValue += RollValue(currentSpell.Dice[0], currentSpell.Dice[0]);
        }

        return spellValue;
    }

    private static SpellSO.Element ElementalAugmentationFunction(Entity spellUser, SpellSO.Element spellType)
    {
        Inventory spellUserInven = spellUser.GetInventory();

        if (spellUserInven.Abilities.Contains(AbilityBrain.GetAbilityList()[95]))
        {
            if (spellType is SpellSO.Element.Normal || spellType is SpellSO.Element.Energy)
            {
                ClimateManager.Weather currentWeather = ClimateManager.Instance.GetWeather();

                spellType = currentWeather switch
                {
                    ClimateManager.Weather.Sunny => SpellSO.Element.Fire,
                    ClimateManager.Weather.Cloudy => SpellSO.Element.Wind,
                    ClimateManager.Weather.Rainy => SpellSO.Element.Water,
                    ClimateManager.Weather.Monsoon => SpellSO.Element.Water,
                    ClimateManager.Weather.Eclipsed => SpellSO.Element.Darkness,
                    ClimateManager.Weather.Snowy => SpellSO.Element.Ice,
                    ClimateManager.Weather.Blizzard => SpellSO.Element.Ice,

                    _ => spellType,
                };
            }
        }

        return spellType;
    }
    private static int UniqueSpellTypeChecks(Spell currentSpell, int spellValue, SpellSO.Element targetType)
    {
        switch (currentSpell.SpellID)
        {
            case 6:                     // Life Extraction attacking Necro Entity check
                if (targetType == SpellSO.Element.Necro)
                    return 0;
                break;
            case 16:                    // Exorcise attacking Light Entity check
                if (targetType is SpellSO.Element.Light)
                    return 0;
                break;
        }

        return spellValue;
    }
    public static int ElementTypeChecks(int damage, Entity attacker, Entity target, Dictionary<int, (List<SpellSO.Element>, List<WeaponSO.Type>)> typesUsed, SortedDictionary<int, (int, Dice)> damageRolls, bool isOffhand = false)
    {
        SpellSO.Element attackerElement;
        if (!isOffhand)
        {
            attackerElement = attacker is Enemy enemy ? enemy.GetEntityType() :
                (attacker.GetInventory().GetPrimaryActiveWeapon() != null ? attacker.GetInventory().GetPrimaryActiveWeapon().WeaponElement : ((Ally)attacker).GetEntityType());
        }
        else
        {
            attackerElement = attacker is Enemy enemy ? enemy.GetEntityType() :
                (attacker.GetInventory().GetSecondaryActiveWeapon() != null ? attacker.GetInventory().GetSecondaryActiveWeapon().WeaponElement : ((Ally)attacker).GetEntityType());
        }
        Dictionary<SpellSO.Element, int> targetWeaknesses = target.GetElementWeaknesses();
        attackerElement = ElementalAugmentationFunction(attacker, attackerElement);

        damage = AbilityBrain.DamageChecks(damage, attackerElement, attacker, target, damageRolls);
        if (target.GetElementResists().ContainsKey(attackerElement))
        {
            int times = target.GetElementResists()[attackerElement] / 25;

            if (typesUsed is not null)
            {
                if (typesUsed.ContainsKey(1))
                {
                    if (!typesUsed[1].Item1.Contains(attackerElement))
                    {
                        List<SpellSO.Element> elementResists = new List<SpellSO.Element>(typesUsed[1].Item1);
                        List<WeaponSO.Type> weaponResists = new List<WeaponSO.Type>(typesUsed[1].Item2);

                        typesUsed.Remove(1);
                        elementResists.Add(attackerElement);
                        typesUsed.Add(1, (elementResists, weaponResists));
                    }
                }
                else
                    typesUsed.Add(1, (new List<SpellSO.Element> { attackerElement }, new List<WeaponSO.Type>()));
            }
            if (times is 4)
                damage = 0;
            else
            {
                for (int i = 0; i < times; ++i)
                    damage /= 2;
            }
        }
        else if (targetWeaknesses.ContainsKey(attackerElement))
        {
            damage *= 2;
            if (typesUsed is not null)
            {
                if (typesUsed.ContainsKey(0))
                {
                    if (!typesUsed[0].Item1.Contains(attackerElement))
                    {
                        List<SpellSO.Element> elementResists = new List<SpellSO.Element>(typesUsed[0].Item1);
                        List<WeaponSO.Type> weaponResists = new List<WeaponSO.Type>(typesUsed[0].Item2);

                        typesUsed.Remove(0);

                        elementResists.Add(attackerElement);

                        typesUsed.Add(0, (elementResists, weaponResists));
                    }
                }
                else
                    typesUsed.Add(0, (new List<SpellSO.Element> { attackerElement }, new List<WeaponSO.Type>()));
            }
        }

        return damage;
    }
    public static int ElementWeaknessAndResistChecks(int damage, SpellSO.Element damageType, Entity target, Entity spellUser = null, Spell spellUsed = null)
    {
        if (spellUser != null && spellUsed != null)
            damage = AbilityBrain.DamageChecks(damage, damageType, spellUser, target, null, spellUsed);

        Dictionary<SpellSO.Element, int> targetWeaknesses = target.GetElementWeaknesses();
        if (target.GetElementResists().ContainsKey(damageType))
        {
            int times = target.GetElementResists()[damageType] / 25;

            if (times is 4)
                damage = 0;
            else
            {
                for (int i = 0; i < times; ++i)
                    damage /= 2;
            }
        }
        else if (targetWeaknesses.ContainsKey(damageType))
            damage *= 2;

        return damage;
    }
    public static int WeaponTypeChecks(int damage, Entity attacker, Entity target, Dictionary<int, (List<SpellSO.Element>, List<WeaponSO.Type>)> typesUsed = null, bool isOffhand = false)
    {
        WeaponSO.Type attackerType;
        if (!isOffhand)
        {
            attackerType = attacker.GetInventory().GetPrimaryActiveWeapon() != null ? attacker.GetInventory().GetPrimaryActiveWeapon().WeaponType :
                (attacker is Ally ally ? ally.attackType : ((Enemy)attacker).GetDamageType());
        }
        else
        {
            attackerType = attacker.GetInventory().GetSecondaryActiveWeapon() != null ? attacker.GetInventory().GetSecondaryActiveWeapon().WeaponType :
                (attacker is Ally ally ? ally.GetInventory().GetSecondaryActiveWeapon().WeaponType : ((Enemy)attacker).GetDamageType());
        }

        Dictionary<WeaponSO.Type, int> weaponResists = target.GetWeaponResists();
        Dictionary<WeaponSO.Type, int> weaponWeaknesses = target.GetWeaponWeaknesses();

        if (weaponWeaknesses.ContainsKey(attackerType))
        {
            damage *= 2;
            if (typesUsed is not null)
            {
                if (typesUsed.ContainsKey(0))
                {
                    if (!typesUsed[0].Item2.Contains(attackerType))
                    {
                        List<SpellSO.Element> elementResists = new List<SpellSO.Element>(typesUsed[0].Item1);
                        List<WeaponSO.Type> resists = new List<WeaponSO.Type>(typesUsed[0].Item2);

                        typesUsed.Remove(0);

                        resists.Add(attackerType);

                        typesUsed.Add(0, (elementResists, resists));
                    }
                }
                else
                    typesUsed.Add(0, (new List<SpellSO.Element>(), new List<WeaponSO.Type> { attackerType }));
            }
        }
        else if (weaponResists.ContainsKey(attackerType))
        {
            int times = weaponResists[attackerType] / 25;

            if (typesUsed is not null)
            {
                if (typesUsed.ContainsKey(1))
                {
                    if (!typesUsed[1].Item2.Contains(attackerType))
                    {
                        List<SpellSO.Element> elementResists = new List<SpellSO.Element>(typesUsed[1].Item1);
                        List<WeaponSO.Type> resists = new List<WeaponSO.Type>(typesUsed[1].Item2);

                        typesUsed.Remove(1);

                        resists.Add(attackerType);

                        typesUsed.Add(1, (elementResists, resists));
                    }
                }
                else
                    typesUsed.Add(1, (new List<SpellSO.Element>(), new List<WeaponSO.Type> { attackerType }));
            }
            if (times is 4)
                damage = 0;
            else
            {
                for (int i = 0; i < times; ++i)
                    damage /= 2;
            }
        }

        return damage;
    }
    public static int DetermineModifierAndCalculate(WeaponSO.Type type, Entity attackingEntity)
    {
        int outputValue = type switch
        {
            // Use STR Mod
            WeaponSO.Type.Sharp => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Strength),
            // Use STR Mod
            WeaponSO.Type.Blunt => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Strength),
            // Use INT Mod
            WeaponSO.Type.Magic => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Intelligence),
            // Use DEX Mod
            WeaponSO.Type.Ranged => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Dexterity),
            // Use DEX Mod
            WeaponSO.Type.Extended => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Dexterity),
            // Use WIS Mod
            WeaponSO.Type.Firearm => attackingEntity.GatherStats().GetStat(EntityStats.Stat.Wisdom),

            _ => throw new InvalidEnumArgumentException(),
        };
        return outputValue;
    }
    public static int ToHitAddDecipher(Dictionary<string, (List<string>, List<object>)> triggers, int toHitRoll)
    {
        foreach (var value in triggers["ToHitAdd"].Item2)
        {
            if (value is float fVal)
                toHitRoll += (int)Math.Floor(toHitRoll * fVal);
            else if (value is int iVal)
                toHitRoll += iVal;
            else if (value is Dice dice)
                toHitRoll += DiceRoller.RollDice(dice);
            else if (value is Dice[] dices)
                toHitRoll += DiceRoller.RollDice(dices);
            else if (value is Dice.DiceR d)
                toHitRoll += RollValue(d);
            else if (value is Dice.DiceR[] ds)
                toHitRoll += RollValue(ds);
            else if (value is List<object> incepValues)
                toHitRoll += (int)incepValues[0];
            else
                throw new TypeLoadException();
        }

        return toHitRoll;
    }
    public static int AddArmorDecipher(Dictionary<string, (List<string>, List<object>)> triggers, int armorValue)
    {
        foreach (var value in triggers["AddArmor"].Item2)
        {
            if (value is float fVal)                                // Multiplier Ratios
                armorValue += (int)Math.Floor(armorValue * fVal);
            else if (value is int iVal)                             // Straight Values
                armorValue += iVal;
            else if (value is Dice dice)                            // Dice Rolls (This and below needs to be optimized better)
                armorValue += DiceRoller.RollDice(dice);
            else if (value is Dice[] dices)                         // Dice Rolls
                armorValue += DiceRoller.RollDice(dices);
            else if (value is Dice.DiceR d)                         // Dice Rolls
                armorValue += RollValue(d);
            else if (value is Dice.DiceR[] ds)                      // Dice Rolls
                armorValue += RollValue(ds);
            else
                throw new TypeLoadException();
        }

        return armorValue;
    }
    public static int ToHitMinusDecipher(Dictionary<string, (List<string>, List<object>)> triggers, int toHitRoll)
    {
        foreach (var value in triggers["ToHitMinus"].Item2)
        {
            if (value is float fVal)
                toHitRoll += (int)Math.Floor(toHitRoll * fVal);
            else if (value is int iVal)
                toHitRoll += iVal;
            else if (value is Dice dice)
                toHitRoll += DiceRoller.RollDice(dice);
            else if (value is Dice[] dices)
                toHitRoll += DiceRoller.RollDice(dices);
            else if (value is Dice.DiceR d)
                toHitRoll += RollValue(d);
            else if (value is Dice.DiceR[] ds)
                toHitRoll += RollValue(ds);
            else
                throw new TypeLoadException();
        }

        return toHitRoll;
    }
    public static int RollSavingThrow(EntityStats.Stat statToBase, Entity entity, Entity spellUser = null, bool isAdvan = false, bool isDisadvan = false)
    {
        if (spellUser != null)
        {
            Dictionary<int, Ability> abList = AbilityBrain.GetAbilityList();
            bool check = spellUser.GetInventory().Abilities.Contains(abList[109]) || spellUser.GetInventory().limitedAbilities.Contains(abList[109]);

            if (check)
                isDisadvan = true;
        }

        EntityStats statRef = entity.GatherStats();

        int savingThrowValue = DiceRoller.RollDice(new DTwenty()) + statRef.GetStat(statToBase);
        if (!isAdvan && isDisadvan)
        {
            isAdvan = statRef.GetModifiedSaveThrows()[statToBase] is 1;
            isDisadvan = statRef.GetModifiedSaveThrows()[statToBase] is -1;
        }

        if (isAdvan && !isDisadvan)
        {
            int newSavingThrowValue = DiceRoller.RollDice(new DTwenty()) + statRef.GetStat(statToBase);

            if (newSavingThrowValue > savingThrowValue)
                savingThrowValue = newSavingThrowValue;
        }
        else if (!isAdvan && isDisadvan)
        {
            int newSavingThrowValue = DiceRoller.RollDice(new DTwenty()) + statRef.GetStat(statToBase);

            if (newSavingThrowValue < savingThrowValue)
                savingThrowValue = newSavingThrowValue;
        }

        if (entity.GatherModList().SmartModCheck("Spiritual Guidance"))
            savingThrowValue += DiceRoller.RollDice(new DFour());

        return savingThrowValue;
    }
    public static Enemy GenerateBounty()
    {
        ClimateManager.Locations randomLoc = ClimateManager.Instance.GetRandomLocation();

        string areaLoad = randomLoc switch
        {
            ClimateManager.Locations.Swamplands             => "Swamplands",
            ClimateManager.Locations.DarkVillage            => "DarkVillage",
            ClimateManager.Locations.AbandonedManor         => "AbandonedManor",
            ClimateManager.Locations.FrozenWasteland        => "FrozenWasteland",

            _ => throw new InvalidEnumArgumentException(),
        };

        List<GameObject> enemyPrefabs = Resources.LoadAll<GameObject>($"Entities/Enemies/{areaLoad}").ToList();
        enemyPrefabs.AddRange(Resources.LoadAll<GameObject>($"Entities/Enemies/General"));

        Enemy enemyGathered = enemyPrefabs[UnityEngine.Random.Range(0, enemyPrefabs.Count)].GetComponent<Enemy>();

        return enemyGathered;
    }

    public static int RetrieveMaxValue(Dice.DiceR indexDice)
    {
        return indexDice switch
        {
            Dice.DiceR.Four => 4,
            Dice.DiceR.Six => 6,
            Dice.DiceR.Eight => 8,
            Dice.DiceR.Ten => 10,
            Dice.DiceR.Twelve => 12,
            Dice.DiceR.Twenty => 20,
            Dice.DiceR.Hundred => 100,

            _ => throw new InvalidEnumArgumentException(),
        };
    }

    public static int MinusArmorDecipher(Dictionary<string, (List<string>, List<object>)> triggers, int armorValue)
    {
        foreach (var value in triggers["MinusArmor"].Item2)
        {
            if (value is float fVal)                                // Multiplier Ratios
                armorValue -= (int)Math.Floor(armorValue * fVal);
            else if (value is int iVal)                             // Straight Values
                armorValue -= iVal;
            else if (value is Dice dice)                            // Dice Rolls (This and below needs to be optimized better)
                armorValue -= DiceRoller.RollDice(dice);
            else if (value is Dice[] dices)                         // Dice Rolls
                armorValue -= DiceRoller.RollDice(dices);
            else if (value is Dice.DiceR d)                         // Dice Rolls
                armorValue -= RollValue(d);
            else if (value is Dice.DiceR[] ds)                      // Dice Rolls
                armorValue -= RollValue(ds);
            else
                throw new TypeLoadException();
        }

        return armorValue;
    }
}