Files
Cielonos/Assets/Scripts/MainGame/Base/BuffSystem/BuffSubmodules.cs

522 lines
18 KiB
C#
Raw Normal View History

2025-12-08 05:27:53 -05:00
using System;
using System.Collections.Generic;
using System.Linq;
using SoftCircuits.Collections;
using SLSFramework.General;
using UnityEngine;
using UnityEngine.Events;
namespace Cielonos.MainGame
{
public partial class BuffBase<T>
{
public abstract class BuffSubmodule : SubmoduleBase<BuffBase<T>>
{
public BuffBase<T> buff;
protected BuffSubmodule(BuffBase<T> buff) : base(buff)
{
this.buff = buff;
}
}
public class ContentSubmodule : BuffSubmodule
{
public string displayName;
public string originalFunctionText;
public string interpretedFunctionText;
public Dictionary<string, Func<string>> parameterGetters;
public ContentSubmodule(BuffBase<T> buff) : base(buff)
{
string displayNameKey = buff.GetType().Name + "_DisplayName";
string originalFunctionTextKey = buff.GetType().Name + "_FunctionText";
this.displayName = displayNameKey.Localize();
this.originalFunctionText = originalFunctionTextKey.Localize();
this.interpretedFunctionText = this.originalFunctionText;
parameterGetters = new Dictionary<string, Func<string>>();
}
public ContentSubmodule(BuffBase<T> buff, string displayNameKey, string originalFunctionTextKey) : base(buff)
{
this.displayName = displayNameKey.Localize();
this.originalFunctionText = originalFunctionTextKey.Localize();
this.interpretedFunctionText = this.originalFunctionText;
parameterGetters = new Dictionary<string, Func<string>>();
}
public ContentSubmodule SetParameterGetter(Dictionary<string, Func<string>> getters)
{
parameterGetters = getters;
return this;
}
public ContentSubmodule AddParameterGetter(string parameterName, Func<string> getter)
{
parameterGetters[parameterName] = getter;
return this;
}
}
public class IconSubmodule : BuffSubmodule
{
public string iconID;
public Sprite icon;
public List<string> synchronizedParameters;
//public HUD_CharacterBuffIcon buffIcon;
public IconSubmodule(BuffBase<T> buff, string iconID = "") : base(buff)
{
if (buff.contentSubmodule != null)
{
this.synchronizedParameters = buff.contentSubmodule.parameterGetters.Keys.ToList();
}
}
public IconSubmodule SetTextFunctions(params string[] syncParameters)
{
synchronizedParameters = syncParameters.ToList();
return this;
}
public void Update()
{
}
public void Remove()
{
}
}
public class EventSubmodule : BuffSubmodule
{
public OrderedDictionary<string, PrioritizedAction<BuffBase<T>>> onOtherBuffApplied; //Buff被添加时参数为被添加的Buff实例
public OrderedDictionary<string, PrioritizedAction<BuffBase<T>>> onOtherBuffFirstApplied; //Buff被新添加时参数为被添加的Buff实例
public OrderedDictionary<string, PrioritizedAction<BuffBase<T>>> onOtherBuffRemoved; //Buff被移除后参数为被移除的Buff实例
public OrderedDictionary<string, PrioritizedAction<AttackResult>> onDealAttack; //造成伤害后,参数为伤害结果
public OrderedDictionary<string, PrioritizedAction<AttackResult>> onGetAttacked; //被攻击后,参数为伤害结果
public EventSubmodule(BuffBase<T> buff) : base(buff)
{
onOtherBuffApplied = new OrderedDictionary<string, PrioritizedAction<BuffBase<T>>>();
onOtherBuffFirstApplied = new OrderedDictionary<string, PrioritizedAction<BuffBase<T>>>();
onOtherBuffRemoved = new OrderedDictionary<string, PrioritizedAction<BuffBase<T>>>();
onDealAttack = new OrderedDictionary<string, PrioritizedAction<AttackResult>>();
onGetAttacked = new OrderedDictionary<string, PrioritizedAction<AttackResult>>();
}
}
public class TimeSubmodule : BuffSubmodule
{
public bool isInfinite;
public float duration;
public float timeLeft;
public float TimeLeftPercentage => timeLeft / duration;
public List<IntervalAction> intervalActions;
public TimeSubmodule(BuffBase<T> buff, bool isInfinite): base(buff)
{
this.buff = buff;
this.isInfinite = isInfinite;
this.duration = -1;
this.timeLeft = -1;
this.intervalActions = new List<IntervalAction>();
}
public TimeSubmodule(BuffBase<T> buff, float duration): base(buff)
{
this.buff = buff;
this.isInfinite = false;
this.duration = duration;
this.timeLeft = duration;
this.intervalActions = new List<IntervalAction>();
}
public void Update(float deltaTime)
{
foreach (var action in intervalActions)
{
action.Update(deltaTime);
}
if (isInfinite)
{
return;
}
timeLeft -= deltaTime;
if (timeLeft <= 0)
{
buff.Remove();
}
}
public void AddIntervalAction(Action action, float interval)
{
intervalActions.Add(new IntervalAction(action, interval));
}
public void RefreshDuration()
{
timeLeft = duration;
}
public void RefreshDuration(float overrideDuration)
{
duration = Mathf.Max(duration, overrideDuration);
timeLeft = duration;
}
public void StackDuration(float additionalDuration)
{
duration += additionalDuration;
timeLeft += additionalDuration;
}
public class IntervalAction
{
public float timer;
float interval;
Action action;
public IntervalAction(Action action, float interval)
{
this.action = action;
this.interval = interval;
this.timer = 0f;
}
public void Update(float deltaTime)
{
timer += deltaTime;
if (timer >= interval)
{
action.Invoke();
timer -= interval;
}
}
}
}
public class CountSubmodule : BuffSubmodule
{
public int maximumCount;
public int remainingCount;
public bool isInfinite => maximumCount < 0;
public float remainingPercentage => (float)remainingCount / maximumCount;
public UnityAction<int> onCountChanged;
/// <summary>
/// maximumCount为负数表示无限持续时间。
/// </summary>
public CountSubmodule(BuffBase<T> buff, int maximumCount = -1) : base(buff)
{
this.maximumCount = maximumCount;
this.remainingCount = maximumCount;
}
public void Update()
{
if (isInfinite)
{
return;
}
remainingCount--;
onCountChanged?.Invoke(remainingCount);
if (remainingCount <= 0)
{
buff.Remove();
}
}
/// <summary>
/// 刷新剩余时间至初始值。
/// </summary>
public void Refresh()
{
if (isInfinite)
{
return;
}
remainingCount = maximumCount;
onCountChanged?.Invoke(remainingCount);
}
/// <summary>
/// 覆盖可选保留更大的duration并刷新剩余时间。
/// </summary>
public void Refresh(int overrideDuration, bool keepMaximal = true)
{
if (isInfinite)
{
return;
}
maximumCount = keepMaximal ? Mathf.Max(maximumCount, overrideDuration) : overrideDuration;
remainingCount = maximumCount;
onCountChanged?.Invoke(remainingCount);
}
/// <summary>
/// 增加持续时间和剩余时间。
/// </summary>
public void AddCount(int maxCount)
{
if (isInfinite)
{
return;
}
maximumCount += maxCount;
remainingCount += maxCount;
onCountChanged?.Invoke(remainingCount);
}
/// <summary>
/// 仅增加剩余时间,不改变总持续时间。
/// 如果增加后剩余时间超过总持续时间,则剩余时间等于总持续时间。
/// </summary>
public void AddRemainingCount(int count)
{
if (isInfinite)
{
return;
}
remainingCount += count;
remainingCount = Mathf.Min(remainingCount, maximumCount);
onCountChanged?.Invoke(remainingCount);
}
/// <summary>
/// 选择更高的持续时间和剩余时间。
/// </summary>
public void PickHigherCount(CountSubmodule other)
{
if (isInfinite)
{
return;
}
maximumCount = Mathf.Max(maximumCount, other.maximumCount);
remainingCount = Mathf.Max(remainingCount, other.remainingCount);
}
}
/// <summary>
/// Buff叠加模块叠加层数统一。
/// </summary>
public class UnitedStackSubmodule : BuffSubmodule
{
public bool willRemoveOnZero; //是否在层数为0时移除Buff
public bool isIntegerRange; //是否为整数范围型Buff可为0或负数
public int stackAmount; //当前层数
public int stackUpperLimit; //层数上限,-1表示无限制
public IBuffExtension_IntegerRange IntegerRange => buff as IBuffExtension_IntegerRange;
public UnitedStackSubmodule(BuffBase<T> buff, int initialStackAmount = 1, bool isIntegerRange = false) : base(buff)
{
this.willRemoveOnZero = true;
this.isIntegerRange = isIntegerRange;
this.stackAmount = initialStackAmount;
this.stackUpperLimit = -1;
}
public UnitedStackSubmodule(BuffBase<T> buff, bool willRemoveOnZero,
int stackUpperLimit = -1, int initialStackAmount = 1, bool isIntegerRange = false) : base(buff)
{
this.willRemoveOnZero = willRemoveOnZero;
this.isIntegerRange = isIntegerRange;
this.stackAmount = initialStackAmount;
this.stackUpperLimit = stackUpperLimit;
}
public void RefreshStackUpperLimit(int upperLimit, bool keepMaximal = true)
{
stackUpperLimit = keepMaximal ? Mathf.Max(stackUpperLimit, upperLimit) : upperLimit;
}
public void PickHigherStack(UnitedStackSubmodule other)
{
stackAmount = Mathf.Max(stackAmount, other.stackAmount);
if (stackUpperLimit > 0)
{
stackAmount = Mathf.Min(stackAmount, stackUpperLimit);
}
}
public void AddStack(int amount) => ModifyStack(amount);
public void ReduceStack(int amount) => ModifyStack(-amount);
public void ModifyStack(int amount)
{
int lastStack = stackAmount;
stackAmount += amount;
if (stackUpperLimit > 0)
{
stackAmount = Mathf.Min(stackAmount, stackUpperLimit);
}
if (willRemoveOnZero)
{
if (!isIntegerRange && stackAmount <= 0)
{
buff.Remove();
return;
}
if (isIntegerRange && stackAmount == 0)
{
buff.Remove();
return;
}
}
if (isIntegerRange)
{
if (lastStack < 0 && stackAmount > 0)
{
IntegerRange.OnBecomePositive();
}
else if (lastStack > 0 && stackAmount < 0)
{
IntegerRange.OnBecomeNegative();
}
else if (lastStack != 0 && stackAmount == 0)
{
IntegerRange.OnBecomeZero();
}
}
}
public void ClearAllStacks()
{
stackAmount = 0;
if (willRemoveOnZero)
{
buff.Remove();
}
}
}
/// <summary>
/// Buff独立叠加模块每一层的持续时间和层数可以不同。
/// </summary>
public class IndependentStackSubmodule : BuffSubmodule
{
public bool willRemoveOnZero;
public List<IndependentStackUnit> independentStacks;
public int totalStackAmount;
public IndependentStackSubmodule(BuffBase<T> buff, bool willRemoveOnZero = true) : base(buff)
{
independentStacks = new List<IndependentStackUnit>();
totalStackAmount = 0;
this.willRemoveOnZero = willRemoveOnZero;
}
public IndependentStackSubmodule(BuffBase<T> buff, int stack, float duration, bool willRemoveOnZero = true) : base(buff)
{
independentStacks = new List<IndependentStackUnit>();
AddStack(stack, duration);
totalStackAmount = stack;
this.willRemoveOnZero = willRemoveOnZero;
}
public void Update(float deltaTime)
{
independentStacks.ForEach(x => x.remainingTime -= deltaTime);
independentStacks.RemoveAll(x => !x.IsInfinite && x.remainingTime <= 0);
totalStackAmount = independentStacks.Sum(x => x.stackAmount);
if (willRemoveOnZero && totalStackAmount <= 0)
{
buff.Remove();
}
}
public IndependentStackUnit LongestUnit => independentStacks.Count > 0 ? independentStacks[^1] : null;
public void Merge(IndependentStackSubmodule other)
{
foreach (IndependentStackUnit stack in other.independentStacks)
{
independentStacks.Add(new IndependentStackUnit(stack.stackAmount, stack.duration));
}
independentStacks.Sort();
}
public void AddStack(int stackAmount, float duration)
{
IndependentStackUnit addition = new IndependentStackUnit(stackAmount, duration);
independentStacks.Add(addition);
independentStacks.Sort();
}
public void ReduceStack(int stackAmount)
{
for (int i = 0; i < independentStacks.Count; i++)
{
if (stackAmount <= independentStacks[i].stackAmount)
{
independentStacks[i].stackAmount -= stackAmount;
if (independentStacks[i].stackAmount <= 0)
{
independentStacks.RemoveAt(i);
}
return;
}
stackAmount -= independentStacks[i].stackAmount;
independentStacks.RemoveAt(i);
i--;
}
totalStackAmount = independentStacks.Sum(x => x.stackAmount);
if (willRemoveOnZero && totalStackAmount <= 0)
{
buff.Remove();
}
}
public class IndependentStackUnit : IComparable<IndependentStackUnit>
{
public int stackAmount;
public float duration;
public float remainingTime;
public Dictionary<string, float> parameters;
public bool IsInfinite => duration < 0;
public IndependentStackUnit(int stackAmount, float duration)
{
this.stackAmount = stackAmount;
this.duration = duration;
this.remainingTime = duration;
this.parameters = new Dictionary<string, float>();
}
public int CompareTo(IndependentStackUnit other)
{
return remainingTime.CompareTo(other.remainingTime);
}
}
}
}
}