Created
March 11, 2022 22:21
-
-
Save phosphoer/adb7e324e3d768720d1012660bf35f82 to your computer and use it in GitHub Desktop.
Stat Modifier Stack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections.Generic; | |
public enum StatModifierTrait | |
{ | |
MaxHealth, | |
Damage, | |
Etc | |
} | |
public enum StatModifierOperation | |
{ | |
Add, | |
Multiply, | |
} | |
[System.Serializable] | |
public class StatModifier | |
{ | |
public string Name => GetName(Trait); | |
public float RemainingTime = Mathf.Infinity; | |
public float Value; | |
public float DisplayMultiplier; | |
public string Units; | |
public StatModifierTrait Trait; | |
public StatModifierOperation Operation; | |
public static string GetName(StatModifierTrait forTrait) | |
{ | |
switch (forTrait) | |
{ | |
case StatModifierTrait.MaxHealth: | |
return "Max Health"; | |
case StatModifierTrait.Damage: | |
return "Damage"; | |
} | |
return $"Unnamed stat {forTrait}"; | |
} | |
} | |
public class StatModifierStack | |
{ | |
public IReadOnlyList<StatModifier> Stats => _stats; | |
public event System.Action<StatModifier> ModifierAdded; | |
public event System.Action<StatModifier> ModifierRemoved; | |
private List<StatModifier> _stats = new List<StatModifier>(); | |
private List<float> _statLifeTimes = new List<float>(); | |
private List<StatModifier>[] _statsByOperation; | |
private CachedValue[] _moddedValuesCache = new CachedValue[System.Enum.GetValues(typeof(StatModifierTrait)).Length]; | |
private struct CachedValue | |
{ | |
public float Value; | |
public float BaseValue; | |
public bool IsValid; | |
} | |
public StatModifierStack() | |
{ | |
_statsByOperation = new List<StatModifier>[System.Enum.GetValues(typeof(StatModifierOperation)).Length]; | |
for (int i = 0; i < _statsByOperation.Length; ++i) | |
{ | |
_statsByOperation[i] = new List<StatModifier>(); | |
} | |
} | |
public bool HasModifier(StatModifier modifier) | |
{ | |
for (int i = 0; i < Stats.Count; ++i) | |
{ | |
if (Stats[i] == modifier) | |
return true; | |
} | |
return false; | |
} | |
public bool HasModifier(string modifierName) | |
{ | |
for (int i = 0; i < Stats.Count; ++i) | |
{ | |
if (Stats[i].Name == modifierName) | |
return true; | |
} | |
return false; | |
} | |
public void Update(float dt) | |
{ | |
for (int i = 0; i < _stats.Count; ++i) | |
{ | |
StatModifier stat = _stats[i]; | |
_statLifeTimes[i] -= dt; | |
if (_statLifeTimes[i] <= 0) | |
{ | |
RemoveModifier(i); | |
--i; | |
} | |
} | |
} | |
public IReadOnlyList<StatModifier> GetModifiersByOperation(StatModifierOperation operation) | |
{ | |
return _statsByOperation[(int)operation]; | |
} | |
public float GetModdedValue(StatModifierTrait trait, float baseValue) | |
{ | |
// Get the cached value | |
CachedValue cache = _moddedValuesCache[(int)trait]; | |
cache.IsValid &= cache.BaseValue == baseValue; | |
// Update the cached value | |
if (!cache.IsValid) | |
{ | |
// Debug.Log($"Recalculating modded stat for trait {trait}"); | |
IReadOnlyList<StatModifier> addMods = GetModifiersByOperation(StatModifierOperation.Add); | |
IReadOnlyList<StatModifier> multMods = GetModifiersByOperation(StatModifierOperation.Multiply); | |
cache.Value = baseValue; | |
for (int i = 0; i < addMods.Count; ++i) | |
{ | |
StatModifier mod = addMods[i]; | |
if (mod.Trait == trait) | |
cache.Value += mod.Value; | |
} | |
for (int i = 0; i < multMods.Count; ++i) | |
{ | |
StatModifier mod = multMods[i]; | |
if (mod.Trait == trait) | |
cache.Value *= mod.Value; | |
} | |
cache.IsValid = true; | |
cache.BaseValue = baseValue; | |
_moddedValuesCache[(int)trait] = cache; | |
// Debug.Log($"Modded trait value is {trait} is {cache.Value}"); | |
} | |
return cache.Value; | |
} | |
public void AddModifiers(StatModifier[] modifiers) | |
{ | |
foreach (StatModifier modifier in modifiers) | |
AddModifier(modifier); | |
} | |
public void RemoveModifiers(StatModifier[] modifiers) | |
{ | |
foreach (StatModifier modifier in modifiers) | |
RemoveModifier(modifier); | |
} | |
public void AddModifier(StatModifier modifier) | |
{ | |
_stats.Add(modifier); | |
_statsByOperation[(int)modifier.Operation].Add(modifier); | |
_statLifeTimes.Add(modifier.RemainingTime); | |
CachedValue cachedValue = _moddedValuesCache[(int)modifier.Trait]; | |
cachedValue.IsValid = false; | |
_moddedValuesCache[(int)modifier.Trait] = cachedValue; | |
ModifierAdded?.Invoke(modifier); | |
} | |
public void RemoveModifier(int index) | |
{ | |
StatModifier modifier = _stats[index]; | |
_stats.RemoveAt(index); | |
_statLifeTimes.RemoveAt(index); | |
_statsByOperation[(int)modifier.Operation].Remove(modifier); | |
CachedValue cachedValue = _moddedValuesCache[(int)modifier.Trait]; | |
cachedValue.IsValid = false; | |
_moddedValuesCache[(int)modifier.Trait] = cachedValue; | |
ModifierRemoved?.Invoke(modifier); | |
} | |
public void RemoveModifier(StatModifier modifier) | |
{ | |
int index = _stats.IndexOf(modifier); | |
if (index >= 0) | |
RemoveModifier(index); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment