Encounter / Assets / Scripts / EntityHandler / EntityStats.cs
EntityStats.cs
Raw
using System;
using UnityEngine;
using System.Collections.Generic;

#if UNITY_EDITOR
using UnityEditor;
#endif

/// <summary>
/// Handles base stats and modifiers for the stats of an entity
/// </summary>
public class EntityStats : MonoBehaviour
{
    public enum Stat
    {
        Strength,
        Wisdom,
        Intelligence,
        Dexterity,
        Charisma,
        Constitution,
        Luck,
        ToHit,
        Armor,
        HPRegen,
        MPRegen,
        Damage,
        CritDamage,
        ToCritMod
    }

    [SerializeField][Range(0, 30)] private int Strength;            // Base STR
    [SerializeField][Range(0, 30)] private int Wisdom;              // Base WIS
    [SerializeField][Range(0, 30)] private int Intelligence;        // Base INT
    [SerializeField][Range(0, 30)] private int Dexterity;           // Base DEX
    [SerializeField][Range(0, 30)] private int Charisma;            // Base CHA
    [SerializeField][Range(0, 30)] private int Constitution;        // Base CON
    [SerializeField][Range(0, 30)] private int Luck;                // Base LCK

    public int StrMod;                                             // Modifier for the stat STR
    public float StrMultiplierMod;
    public List<Dice.DiceR> StrModDice;
    public int WisMod;                                             // Modifier for the stat WIS
    public float WisMultiplierMod;
    public List<Dice.DiceR> WisModDice;
    public int IntMod;                                             // Modifier for the stat INT
    public float IntMultiplierMod;
    public List<Dice.DiceR> IntModDice;
    public int DexMod;                                             // Modifier for the stat DEX
    public float DexMultiplierMod;
    public List<Dice.DiceR> DexModDice;
    public int ChaMod;                                             // Modifier for the stat CHA
    public float ChaMultiplierMod;
    public List<Dice.DiceR> ChaModDice;
    public int ConMod;                                             // Modifier for the stat CON
    public float ConMultiplierMod;
    public List<Dice.DiceR> ConModDice;
    public int LckMod;                                             // Modifier for the stat LCK
    public float LckMultiplierMod;
    public List<Dice.DiceR> LckModDice;
    public int BaseToHitMod;                                       // Modifier for the To Hit Value
    public float BaseToHitMultiplierMod;
    public List<Dice.DiceR> BaseToHitModDice;
    public int ArmorMod;                                           // Modifier for the Armor value
    public float ArmorMultiplierMod;
    public List<Dice.DiceR> ArmorModDice;
    public int HPRegenMod;                                         // Modifier for health regeneration
    public float HPRegenMultiplierMod;
    public List<Dice.DiceR> HPRegenModDice;
    public int MPRegenMod;                                         // Modifier for the mana regeneration
    public float MPRegenMultiplierMod;
    public List<Dice.DiceR> MPRegenModDice;
    public int DamageMod;                                          // Modifier for damage
    public float DamageMultiplierMod;
    public List<Dice.DiceR> DamageModDice;
    public int ToCritMod;                                          // Modifier for crit chance, 0 represents 20, 1 represents 19
    public float ToCritMultiplierMod;
    public List<Dice.DiceR> ToCritModDice;
    public int CritDamageMod;                                      // Modifier for crit damage
    public float CritDamageMultiplierMod;
    public List<Dice.DiceR> CritDamageModDice;

    public Dictionary<WeaponSO.Type, int> WeaponResistances;
    public Dictionary<SpellSO.Element, int> ElementResistances;
    public Dictionary<WeaponSO.Type, int> WeaponWeaknesses;
    public Dictionary<SpellSO.Element, int> ElementWeaknesses;

    // 0 is not affected, -1 is disadvantaged, 1 is advantaged
    public Dictionary<Stat, int> StatSavingThrowModifications = new Dictionary<Stat, int>()
    {
        { Stat.Strength,        0 },
        { Stat.Intelligence,    0 },
        { Stat.Dexterity,       0 },
        { Stat.Constitution,    0 },
        { Stat.Charisma,        0 },
        { Stat.Wisdom,          0 },
        { Stat.Luck,            0 },
    };

    /// <summary>
    /// Retrieves the stat based on the Stat enum passed for the entity this instance of EntityStats is attached to
    /// </summary>
    /// <param name="stat">The specific Stat to find</param>
    /// <returns>The stat value that is desired</returns>
    /// <exception cref="ArgumentNullException">When a Stat is not given an exception is thrown</exception>
    public int GetStat(Stat stat, int baseValue = 0)
    {
        StrModDice          ??= new List<Dice.DiceR>();
        WisModDice          ??= new List<Dice.DiceR>();
        IntModDice          ??= new List<Dice.DiceR>();
        DexModDice          ??= new List<Dice.DiceR>();
        ChaModDice          ??= new List<Dice.DiceR>();
        ConModDice          ??= new List<Dice.DiceR>();
        LckModDice          ??= new List<Dice.DiceR>();
        BaseToHitModDice    ??= new List<Dice.DiceR>();
        DamageModDice       ??= new List<Dice.DiceR>();
        ToCritModDice       ??= new List<Dice.DiceR>();
        CritDamageModDice   ??= new List<Dice.DiceR>();
        HPRegenModDice      ??= new List<Dice.DiceR>();
        MPRegenModDice      ??= new List<Dice.DiceR>();
        ArmorModDice        ??= new List<Dice.DiceR>();

        return stat switch
        {
            Stat.Strength               => this.StrMod + (int)(this.Strength * this.StrMultiplierMod) + UtilityHandler.RollValue(StrModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Strength)),
            Stat.Wisdom                 => this.WisMod + (int)(this.Wisdom * this.WisMultiplierMod) + UtilityHandler.RollValue(WisModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Wisdom)),
            Stat.Intelligence           => this.IntMod + (int)(this.Intelligence * this.IntMultiplierMod) + UtilityHandler.RollValue(IntModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Intelligence)),
            Stat.Dexterity              => this.DexMod + (int)(this.Dexterity * this.DexMultiplierMod) + UtilityHandler.RollValue(DexModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Dexterity)),
            Stat.Charisma               => this.ChaMod + (int)(this.Charisma * this.ChaMultiplierMod) + UtilityHandler.RollValue(ChaModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Charisma)),
            Stat.Constitution           => this.ConMod + (int)(this.Constitution * this.ConMultiplierMod) + UtilityHandler.RollValue(ConModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Constitution)),
            Stat.Luck                   => this.LckMod + (int)(this.Luck * this.LckMultiplierMod) + UtilityHandler.RollValue(LckModDice.ToArray()) + Globals.GatherModifier(GetBaseStat(Stat.Luck)),
            Stat.ToHit                  => this.BaseToHitMod + (int)(baseValue * this.BaseToHitMultiplierMod) + UtilityHandler.RollValue(BaseToHitModDice.ToArray()),
            Stat.Damage                 => baseValue + this.DamageMod + (int)(baseValue * this.DamageMultiplierMod) + UtilityHandler.RollValue(DamageModDice.ToArray()),
            Stat.ToCritMod              => this.ToCritMod + (int)(20 * this.ToCritMultiplierMod) + UtilityHandler.RollValue(ToCritModDice.ToArray()),
            Stat.CritDamage             => this.CritDamageMod + (int)(baseValue * this.CritDamageMultiplierMod) + UtilityHandler.RollValue(CritDamageModDice.ToArray()),
            Stat.HPRegen                => this.HPRegenMod + (int)(baseValue * this.HPRegenMultiplierMod) + UtilityHandler.RollValue(HPRegenModDice.ToArray()),
            Stat.MPRegen                => this.MPRegenMod + (int)(baseValue * this.MPRegenMultiplierMod) + UtilityHandler.RollValue(MPRegenModDice.ToArray()),
            Stat.Armor                  => baseValue + this.ArmorMod + (int)(baseValue * this.ArmorMultiplierMod) + UtilityHandler.RollValue(ArmorModDice.ToArray()),

            _ => throw new ArgumentNullException("Unknown stat detected"),
        };
    }
    public int GetBaseStat(Stat stat)
    {
        return stat switch
        {
            Stat.Strength               => this.Strength,
            Stat.Wisdom                 => this.Wisdom,
            Stat.Intelligence           => this.Intelligence,
            Stat.Dexterity              => this.Dexterity,
            Stat.Charisma               => this.Charisma,
            Stat.Constitution           => this.Constitution,
            Stat.Luck                   => this.Luck,

            _ => throw new ArgumentNullException("Unknown stat detected"),
        };
    }
    /// <summary>
    /// Sets the stats within the Entity Stats class, primarily meant for the Player Class to connect with the handler stats
    /// </summary>
    /// <param name="statName">Name of the stat to change</param>
    /// <param name="statValue">Value of the stat to set</param>
    /// <exception cref="ArgumentException">Exception is thrown when an unknown name is given</exception>
    public void SetStat(string statName, int statValue)
    {
        switch (statName)
        {
            case "STR":
                this.Strength = statValue; 
                break;
            case "INT":
                this.Intelligence = statValue; 
                break;
            case "DEX":
                this.Dexterity = statValue;
                break;
            case "WIS":
                this.Wisdom = statValue;
                break;
            case "CON":
                this.Constitution = statValue;
                break;
            case "CHA":
                this.Charisma = statValue;
                break;
            case "LCK":
                this.Luck = statValue;
                break;
            default:
                throw new ArgumentException("Unknown stat name indicated, please check that proper stat name was indicated ---> " + statName);
        }
    }
    public void SetModifierToStat(Stat stat, object modification)
    {
        if (modification is int iVal)
        {
            switch (stat)
            {
                case Stat.Strength:
                    StrMod += iVal;
                    break;
                case Stat.Wisdom:
                    WisMod += iVal;
                    break;
                case Stat.Intelligence:
                    IntMod += iVal;
                    break;
                case Stat.Dexterity:
                    DexMod += iVal;
                    break;
                case Stat.Charisma:
                    ChaMod += iVal;
                    break;
                case Stat.Constitution:
                    ConMod += iVal;
                    break;
                case Stat.Luck:
                    LckMod += iVal;
                    break;
                case Stat.Damage:
                    DamageMod += iVal;
                    break;
                case Stat.ToCritMod:
                    ToCritMod += iVal;
                    break;
                case Stat.CritDamage:
                    CritDamageMod += iVal;
                    break;
                case Stat.HPRegen:
                    HPRegenMod += iVal;
                    break;
                case Stat.MPRegen:
                    MPRegenMod += iVal;
                    break;
                case Stat.ToHit:
                    BaseToHitMod += iVal;
                    break;
                case Stat.Armor:
                    ArmorMod += iVal;
                    break;
            }
        }
        else if (modification is float fVal)
        {
            switch (stat)
            {
                case Stat.Strength:
                    StrMultiplierMod += fVal;
                    break;
                case Stat.Wisdom:
                    WisMultiplierMod += fVal;
                    break;
                case Stat.Intelligence:
                    IntMultiplierMod += fVal;
                    break;
                case Stat.Dexterity:
                    DexMultiplierMod += fVal;
                    break;
                case Stat.Charisma:
                    ChaMultiplierMod += fVal;
                    break;
                case Stat.Constitution:
                    ConMultiplierMod += fVal;
                    break;
                case Stat.Luck:
                    LckMultiplierMod += fVal;
                    break;
                case Stat.Damage:
                    DamageMultiplierMod += fVal;
                    break;
                case Stat.ToCritMod:
                    ToCritMultiplierMod += fVal;
                    break;
                case Stat.CritDamage:
                    CritDamageMultiplierMod += fVal;
                    break;
                case Stat.HPRegen:
                    HPRegenMultiplierMod += fVal;
                    break;
                case Stat.MPRegen:
                    MPRegenMultiplierMod += fVal;
                    break;
                case Stat.ToHit:
                    BaseToHitMultiplierMod += fVal;
                    break;
                case Stat.Armor:
                    ArmorMultiplierMod += fVal;
                    break;
            }
        }
        else if (modification is Dice.DiceR[] dices)
        {
            switch (stat)
            {
                case Stat.Strength:
                    StrModDice ??= new List<Dice.DiceR>();
                    StrModDice.AddRange(dices);
                    break;
                case Stat.Wisdom:
                    WisModDice ??= new List<Dice.DiceR>();
                    WisModDice.AddRange(dices);
                    break;
                case Stat.Intelligence:
                    IntModDice ??= new List<Dice.DiceR>();
                    IntModDice.AddRange(dices);
                    break;
                case Stat.Dexterity:
                    DexModDice ??= new List<Dice.DiceR>();
                    DexModDice.AddRange(dices);
                    break;
                case Stat.Charisma:
                    ChaModDice ??= new List<Dice.DiceR>();
                    ChaModDice.AddRange(dices);
                    break;
                case Stat.Constitution:
                    ConModDice ??= new List<Dice.DiceR>();
                    ConModDice.AddRange(dices);
                    break;
                case Stat.Luck:
                    LckModDice ??= new List<Dice.DiceR>();
                    LckModDice.AddRange(dices);
                    break;
                case Stat.Damage:
                    DamageModDice ??= new List<Dice.DiceR>();
                    DamageModDice.AddRange(dices);
                    break;
                case Stat.ToCritMod:
                    ToCritModDice ??= new List<Dice.DiceR>();
                    ToCritModDice.AddRange(dices);
                    break;
                case Stat.CritDamage:
                    CritDamageModDice ??= new List<Dice.DiceR>();
                    CritDamageModDice.AddRange(dices);
                    break;
                case Stat.HPRegen:
                    HPRegenModDice ??= new List<Dice.DiceR>();
                    HPRegenModDice.AddRange(dices);
                    break;
                case Stat.MPRegen:
                    MPRegenModDice ??= new List<Dice.DiceR>();
                    MPRegenModDice.AddRange(dices);
                    break;
                case Stat.ToHit:
                    BaseToHitModDice ??= new List<Dice.DiceR>();
                    BaseToHitModDice.AddRange(dices);
                    break;
                case Stat.Armor:
                    ArmorModDice ??= new List<Dice.DiceR>();
                    ArmorModDice.AddRange(dices);
                    break;
            }
        }
    }
    public void RemoveModifierToStat(Stat stat, object modification)
    {
        if (modification is int iVal)
        {
            switch (stat)
            {
                case Stat.Strength:
                    StrMod -= iVal;
                    break;
                case Stat.Wisdom:
                    WisMod -= iVal;
                    break;
                case Stat.Intelligence:
                    IntMod -= iVal;
                    break;
                case Stat.Dexterity:
                    DexMod -= iVal;
                    break;
                case Stat.Charisma:
                    ChaMod -= iVal;
                    break;
                case Stat.Constitution:
                    ConMod -= iVal;
                    break;
                case Stat.Luck:
                    LckMod -= iVal;
                    break;
                case Stat.Damage:
                    DamageMod -= iVal;
                    break;
                case Stat.ToCritMod:
                    ToCritMod -= iVal;
                    break;
                case Stat.CritDamage:
                    CritDamageMod -= iVal;
                    break;
                case Stat.HPRegen:
                    HPRegenMod -= iVal;
                    break;
                case Stat.MPRegen:
                    MPRegenMod -= iVal;
                    break;
                case Stat.ToHit:
                    BaseToHitMod -= iVal;
                    break;
                case Stat.Armor:
                    ArmorMod -= iVal;
                    break;
            }
        }
        else if (modification is float fVal)
        {
            switch (stat)
            {
                case Stat.Strength:
                    StrMultiplierMod -= fVal;
                    break;
                case Stat.Wisdom:
                    WisMultiplierMod -= fVal;
                    break;
                case Stat.Intelligence:
                    IntMultiplierMod -= fVal;
                    break;
                case Stat.Dexterity:
                    DexMultiplierMod -= fVal;
                    break;
                case Stat.Charisma:
                    ChaMultiplierMod -= fVal;
                    break;
                case Stat.Constitution:
                    ConMultiplierMod -= fVal;
                    break;
                case Stat.Luck:
                    LckMultiplierMod -= fVal;
                    break;
                case Stat.Damage:
                    DamageMultiplierMod -= fVal;
                    break;
                case Stat.ToCritMod:
                    ToCritMultiplierMod -= fVal;
                    break;
                case Stat.CritDamage:
                    CritDamageMultiplierMod -= fVal;
                    break;
                case Stat.HPRegen:
                    HPRegenMultiplierMod -= fVal;
                    break;
                case Stat.MPRegen:
                    MPRegenMultiplierMod -= fVal;
                    break;
                case Stat.ToHit:
                    BaseToHitMultiplierMod -= fVal;
                    break;
                case Stat.Armor:
                    ArmorMultiplierMod -= fVal;
                    break;
            }
        }
        else if (modification is Dice.DiceR[] dices)
        {
            switch (stat)
            {
                case Stat.Strength:
                    foreach (Dice.DiceR dice in dices)
                        StrModDice.Remove(dice);
                    break;
                case Stat.Wisdom:
                    foreach (Dice.DiceR dice in dices)
                        WisModDice.Remove(dice);
                    break;
                case Stat.Intelligence:
                    foreach (Dice.DiceR dice in dices)
                        IntModDice.Remove(dice);
                    break;
                case Stat.Dexterity:
                    foreach (Dice.DiceR dice in dices)
                        DexModDice.Remove(dice);
                    break;
                case Stat.Charisma:
                    foreach (Dice.DiceR dice in dices)
                        ChaModDice.Remove(dice);
                    break;
                case Stat.Constitution:
                    foreach (Dice.DiceR dice in dices)
                        ConModDice.Remove(dice);
                    break;
                case Stat.Luck:
                    foreach (Dice.DiceR dice in dices)
                        LckModDice.Remove(dice);
                    break;
                case Stat.Damage:
                    foreach (Dice.DiceR dice in dices)
                        DamageModDice.Remove(dice);
                    break;
                case Stat.ToCritMod:
                    foreach (Dice.DiceR dice in dices)
                        ToCritModDice.Remove(dice);
                    break;
                case Stat.CritDamage:
                    foreach (Dice.DiceR dice in dices)
                        CritDamageModDice.Remove(dice);
                    break;
                case Stat.HPRegen:
                    foreach (Dice.DiceR dice in dices)
                        HPRegenModDice.Remove(dice);
                    break;
                case Stat.MPRegen:
                    foreach (Dice.DiceR dice in dices)
                        MPRegenModDice.Remove(dice);
                    break;
                case Stat.ToHit:
                    foreach (Dice.DiceR dice in dices)
                        BaseToHitModDice.Remove(dice);
                    break;
                case Stat.Armor:
                    foreach (Dice.DiceR dice in dices)
                        ArmorModDice.Remove(dice);
                    break;
            }
        }
    }
    /// <summary>
    /// Resets a specific modification based on the Enum passed
    /// </summary>
    /// <param name="stat"></param>
    public void ResetMod(Stat stat)
    {
        switch (stat)
        {
            case Stat.Strength: 
                this.StrMod = 0; 
                break;
            case Stat.Wisdom: 
                this.WisMod = 0; 
                break;
            case Stat.Intelligence: 
                this.IntMod = 0; 
                break;
            case Stat.Dexterity: 
                this.DexMod = 0; 
                break;
            case Stat.Charisma: 
                this.ChaMod = 0; 
                break;
            case Stat.Constitution: 
                this.ConMod = 0; 
                break;
            case Stat.Luck: 
                this.LckMod = 0;
                break;
            case Stat.ToHit:
                this.BaseToHitMod = 0;
                break;
            case Stat.Armor: 
                this.ArmorMod = 0;
                break;
            case Stat.HPRegen: 
                this.HPRegenMod = 0;
                break;
            case Stat.MPRegen:
                this.MPRegenMod = 0;
                break;
            case Stat.Damage: 
                this.DamageMod = 0;
                break;
            case Stat.CritDamage:
                this.CritDamageMod = 0;
                break;
        }
    }
    /// <summary>
    /// Resets all of the mods attached to this entity
    /// </summary>
    public void ResetAllMods()
    {
        this.StrMod             = 0;
        this.WisMod             = 0;
        this.DexMod             = 0;
        this.ChaMod             = 0;
        this.ConMod             = 0;
        this.IntMod             = 0;
        this.LckMod             = 0;
        this.BaseToHitMod       = 0;
        this.ArmorMod           = 0;
        this.HPRegenMod         = 0;
        this.MPRegenMod         = 0;
        this.DamageMod          = 0;
        this.CritDamageMod      = 0;
    }
    /// <summary>
    /// Adds an elemental resistance to this entity's stats
    /// </summary>
    /// <param name="newResistance">Resisted element to be recorded</param>
    public void AddElementalResistance(SpellSO.Element newResistance)
    {
        this.ElementResistances ??= new Dictionary<SpellSO.Element, int>();
        if (!this.ElementResistances.ContainsKey(newResistance))
            this.ElementResistances.Add(newResistance, 25);
        else
            this.ElementResistances[newResistance] += 25;
    }
    /// <summary>
    /// Remvoes an elemental resistance either completely or partially from this entity's stats
    /// </summary>
    /// <param name="removedResistance">The resistance to remove from this entity's stats</param>
    /// <param name="partially">Indicator if only a percentage of the resistance should be cut off</param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public void RemoveElementalResistance(SpellSO.Element removedResistance, bool partially = false)
    {
        if (this.ElementResistances.ContainsKey(removedResistance) && !partially)
            this.ElementResistances.Remove(removedResistance);
        else if (this.ElementResistances.ContainsKey(removedResistance) && partially)
        {
            int currentResist = this.ElementResistances[removedResistance];
            currentResist -= 25;
            if (currentResist <= 0)
            {
                this.ElementResistances.Remove(removedResistance);
                return;
            }

            this.ElementResistances[removedResistance] = currentResist;
        }
        else
            throw new ArgumentOutOfRangeException($"Unable to remove ({removedResistance}) out of Elemental Resistance list due to list not containing resistance element.");
    }
    /// <summary>
    /// Adds an elemental weakness to this entity's stats
    /// </summary>
    /// <param name="newWeakness">The new elemental weakness to add</param>
    public void AddElementalWeakness(SpellSO.Element newWeakness)
    {
        this.ElementWeaknesses ??= new Dictionary<SpellSO.Element, int>();
        if (!this.ElementWeaknesses.ContainsKey(newWeakness))
            this.ElementWeaknesses.Add(newWeakness, 25);
        else
            this.ElementWeaknesses[newWeakness] += 25;
    }
    /// <summary>
    /// Removes an elemental weakness from this entity's stats
    /// </summary>
    /// <param name="removedWeakness">The elemental weakness to remove</param>
    /// <param name="partially">Indicator if the weakness should be completely or partially removed</param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public void RemoveElementalWeakness(SpellSO.Element removedWeakness, bool partially = false)
    {
        if (this.ElementWeaknesses.ContainsKey(removedWeakness) && !partially)
            this.ElementWeaknesses.Remove(removedWeakness);
        else if (this.ElementWeaknesses.ContainsKey(removedWeakness) && partially)
        {
            int currentResist = this.ElementWeaknesses[removedWeakness];
            currentResist -= 25;
            if (currentResist <= 0)
            {
                this.ElementWeaknesses.Remove(removedWeakness);
                return;
            }

            this.ElementWeaknesses[removedWeakness] = currentResist;
        }
        else
            throw new ArgumentOutOfRangeException($"Unable to remove ({removedWeakness}) out of Elemental Resistance list due to list not containing resistance element.");
    }
    /// <summary>
    /// Adds a weapon type resistance to this entity's stats
    /// </summary>
    /// <param name="weaponType">The resistance to add to this entity's stats</param>
    public void AddTypeResistance(WeaponSO.Type weaponType)
    {
        this.WeaponResistances ??= new Dictionary<WeaponSO.Type, int>();
        if (!this.WeaponResistances.ContainsKey(weaponType))
            this.WeaponResistances.Add(weaponType, 25);
        else
            this.WeaponResistances[weaponType] += 25;
    }
    /// <summary>
    /// Removes a weapon type resistance either partially or completely
    /// </summary>
    /// <param name="weaponType">The weapon type resistance to remove</param>
    /// <param name="partially">Indicator if all of the resistance should be removed or only a percentage</param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public void RemoveTypeResistance(WeaponSO.Type weaponType, bool partially = false)
    {
        if (this.WeaponResistances.ContainsKey(weaponType) && !partially)
            this.WeaponResistances.Remove(weaponType);
        else if (this.WeaponResistances.ContainsKey(weaponType) && partially)
        {
            int currentResist = this.WeaponResistances[weaponType];
            currentResist -= 25;
            if (currentResist <= 0)
            {
                this.WeaponResistances.Remove(weaponType);
                return;
            }

            this.WeaponResistances[weaponType] = currentResist;
        }
        else
            throw new ArgumentOutOfRangeException($"Unable to remove ({weaponType}) out of Elemental Resistance list due to list not containing resistance element.");
    }
    /// <summary>
    /// Adds a weapon type weakness to this entity's stats
    /// </summary>
    /// <param name="weaponType">The weapon weakness type to add</param>
    public void AddTypeWeakness(WeaponSO.Type weaponType)
    {
        this.WeaponWeaknesses ??= new Dictionary<WeaponSO.Type, int>();
        if (!this.WeaponWeaknesses.ContainsKey(weaponType))
            this.WeaponWeaknesses.Add(weaponType, 25);
        else
            this.WeaponWeaknesses[weaponType] += 25;
    }
    /// <summary>
    /// Removes a weapon weakness either completely or partially
    /// </summary>
    /// <param name="weaponType">The weapon weakness type to remove</param>
    /// <param name="partially">Indicator if the weakness is partially removed or completely removed</param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public void RemoveTypeWeakness(WeaponSO.Type weaponType, bool partially = false)
    {
        if (this.WeaponWeaknesses.ContainsKey(weaponType) && !partially)
            this.WeaponWeaknesses.Remove(weaponType);
        else if (this.WeaponWeaknesses.ContainsKey(weaponType) && partially)
        {
            int currentResist = this.WeaponWeaknesses[weaponType];
            currentResist -= 25;
            if (currentResist <= 0)
            {
                this.WeaponWeaknesses.Remove(weaponType);
                return;
            }

            this.WeaponWeaknesses[weaponType] = currentResist;
        }
        else
            throw new ArgumentOutOfRangeException($"Unable to remove ({weaponType}) out of Elemental Resistance list due to list not containing resistance element.");
    }

    /// <summary>
    /// Changes a certain stat to incorporate disadvantages or advantages
    /// </summary>
    /// <param name="stat">The stat to modify</param>
    /// <param name="value">
    /// 0 --> No Change
    /// 1 --> Advantaged
    /// -1 --> Disadvantaged
    /// </param>
    public void ModifySavingThrow(Stat stat, int value)
    {
        StatSavingThrowModifications[stat] = value;
    }
    public Dictionary<Stat, int> GetModifiedSaveThrows()
        => StatSavingThrowModifications;
}

#if UNITY_EDITOR
[CustomEditor(typeof(EntityStats))]
public class EntityStatsEditor : Editor
{
    private EntityStats container;

    private void OnEnable()
    {
        container = target as EntityStats;
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        GUI.changed = false;

        EditorGUILayout.LabelField("Base Stats", EditorStyles.boldLabel);
        EditorGUILayout.Space(10);

        EditorGUILayout.PropertyField(serializedObject.FindProperty("Strength"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Wisdom"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Intelligence"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Dexterity"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Charisma"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Constitution"));
        EditorGUILayout.PropertyField(serializedObject.FindProperty("Luck"));

        if (GUI.changed)
            EditorUtility.SetDirty(container);

        serializedObject.ApplyModifiedProperties();
    }
}
#endif