181 lines
4.5 KiB
C#
181 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using SepCore.Definition;
|
|
using UnityEngine;
|
|
|
|
namespace SepCore.Battle
|
|
{
|
|
/// <summary>
|
|
/// 单个属性实例容器。
|
|
/// 维护基础值、修饰器列表,通过脏标记(Dirty Flag)缓存计算结果,并基于 StatConfig 进行边界钳制。
|
|
/// </summary>
|
|
public sealed class CharacterStat
|
|
{
|
|
private readonly List<StatModifier> _modifiers = new();
|
|
private float _baseValue;
|
|
private bool _isDirty = true;
|
|
private float _cachedValue;
|
|
private StatConfig _config;
|
|
|
|
public StatType Type { get; }
|
|
|
|
public StatConfig Config
|
|
{
|
|
get
|
|
{
|
|
if (_config == null && GameEntry.Luban != null && GameEntry.Luban.IsReady)
|
|
{
|
|
_config = GameEntry.Luban.Get<StatConfig>((int)Type);
|
|
}
|
|
|
|
return _config;
|
|
}
|
|
set
|
|
{
|
|
_config = value;
|
|
_isDirty = true;
|
|
}
|
|
}
|
|
|
|
public float BaseValue
|
|
{
|
|
get => _baseValue;
|
|
set
|
|
{
|
|
if (Math.Abs(_baseValue - value) > 1e-6f)
|
|
{
|
|
_baseValue = value;
|
|
_isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public float Value
|
|
{
|
|
get
|
|
{
|
|
if (_isDirty)
|
|
{
|
|
_cachedValue = CalculateFinalValue();
|
|
_isDirty = false;
|
|
}
|
|
|
|
return _cachedValue;
|
|
}
|
|
}
|
|
|
|
public IReadOnlyList<StatModifier> Modifiers => _modifiers;
|
|
|
|
public CharacterStat(StatType type, float baseValue = 0f, StatConfig config = null)
|
|
{
|
|
Type = type;
|
|
_baseValue = baseValue;
|
|
_config = config;
|
|
_isDirty = true;
|
|
}
|
|
|
|
public void AddModifier(StatModifier modifier)
|
|
{
|
|
if (modifier == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(modifier));
|
|
}
|
|
|
|
_modifiers.Add(modifier);
|
|
_isDirty = true;
|
|
}
|
|
|
|
public bool RemoveModifier(StatModifier modifier)
|
|
{
|
|
if (modifier == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_modifiers.Remove(modifier))
|
|
{
|
|
_isDirty = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public int RemoveAllModifiersFromSource(object source)
|
|
{
|
|
if (source == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int removed = _modifiers.RemoveAll(m => ReferenceEquals(m.Source, source) || Equals(m.Source, source));
|
|
if (removed > 0)
|
|
{
|
|
_isDirty = true;
|
|
}
|
|
|
|
return removed;
|
|
}
|
|
|
|
public void ClearModifiers()
|
|
{
|
|
if (_modifiers.Count > 0)
|
|
{
|
|
_modifiers.Clear();
|
|
_isDirty = true;
|
|
}
|
|
}
|
|
|
|
public void MarkDirty()
|
|
{
|
|
_isDirty = true;
|
|
}
|
|
|
|
private float CalculateFinalValue()
|
|
{
|
|
float sumFlat = 0f;
|
|
float sumPercentAdd = 0f;
|
|
float prodPercentMult = 1f;
|
|
|
|
for (int i = 0; i < _modifiers.Count; i++)
|
|
{
|
|
StatModifier mod = _modifiers[i];
|
|
switch (mod.Type)
|
|
{
|
|
case ModifierType.Flat:
|
|
sumFlat += mod.Value;
|
|
break;
|
|
case ModifierType.PercentAdd:
|
|
sumPercentAdd += mod.Value;
|
|
break;
|
|
case ModifierType.PercentMult:
|
|
prodPercentMult *= mod.Value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
float finalValue = ((_baseValue + sumFlat) * (1f + sumPercentAdd)) * prodPercentMult;
|
|
return ClampStat(finalValue);
|
|
}
|
|
|
|
private float ClampStat(float value)
|
|
{
|
|
StatConfig config = Config;
|
|
if (config != null)
|
|
{
|
|
if (config.HasMin && value < config.MinValue)
|
|
{
|
|
value = config.MinValue;
|
|
}
|
|
|
|
if (config.HasMax && value > config.MaxValue)
|
|
{
|
|
value = config.MaxValue;
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|
|
}
|