RiftMayhem/Assets/Character Stats/CharacterStat.cs
Pedro Gomes 8917c36ad8 Character Stat revamp (wip)
- working max health, properly setting health component values and showing scales on UI
- working armor & magic resistance, properly mitigating incoming damage based on damage type
2024-08-13 22:36:01 +01:00

126 lines
2.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using UnityEngine.Events;
namespace Kryz.CharacterStats
{
[Serializable]
public class CharacterStat
{
public GameTag statTag;
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<StatModifier> statModifiers;
public readonly ReadOnlyCollection<StatModifier> StatModifiers;
public CharacterStat()
{
statModifiers = new List<StatModifier>();
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);
}
}
}