using System; using System.Collections.Generic; using SepCore.Definition; using UnityEngine; namespace SepCore.Battle { /// /// 单个属性实例容器。 /// 维护基础值、修饰器列表,通过脏标记(Dirty Flag)缓存计算结果,并基于 StatConfig 进行边界钳制。 /// public sealed class CharacterStat { private readonly List _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((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 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; } } }