Files
Cielonos/Assets/Scripts/MainGame/Base/BuffSystem/BuffSubmodules.cs
SoulliesOfficial 72756712f7 UI调整
2026-05-27 15:15:28 -04:00

572 lines
20 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using SoftCircuits.Collections;
using SLSUtilities.General;
using UnityEngine;
using UnityEngine.Events;
namespace Cielonos.MainGame.Buffs
{
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<Attack.Result>> onDealAttack; //造成伤害后,参数为伤害结果
public OrderedDictionary<string, PrioritizedAction<AttackAreaBase, Attack.Context>> onBeforeGetAttacked; //被攻击前,参数为攻击上下文
public OrderedDictionary<string, PrioritizedAction<AttackAreaBase, Attack.Result>> onAfterGetAttacked; //被攻击后,参数为伤害结果
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<Attack.Result>>();
onBeforeGetAttacked = new OrderedDictionary<string, PrioritizedAction<AttackAreaBase, Attack.Context>>();
onAfterGetAttacked = new OrderedDictionary<string, PrioritizedAction<AttackAreaBase, Attack.Result>>();
}
}
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 PickHigherDuration(TimeSubmodule other)
{
duration = Mathf.Max(duration, other.duration);
timeLeft = duration;
}
public void AddDuration(TimeSubmodule other)
{
duration += other.duration;
timeLeft += other.duration;
}
public void AddDuration(float additionalDuration)
{
duration += additionalDuration;
timeLeft += additionalDuration;
}
public class IntervalAction
{
public float timer;
public 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 void SetInterval(float interval)
{
this.interval = interval;
if (timer > interval)
{
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 bool ReachedUpperLimit()
{
if (stackUpperLimit < 0)
{
return false;
}
return stackAmount >= stackUpperLimit;
}
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 IndependentStackSubmodule(BuffBase<T> buff, int stack, float duration,
bool willRemoveOnZero, out IndependentStackUnit unit) : base(buff)
{
independentStacks = new List<IndependentStackUnit>();
unit = 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(stack.Clone());
}
independentStacks.Sort();
}
public IndependentStackUnit AddStack(int stackAmount, float duration)
{
IndependentStackUnit addition = new IndependentStackUnit(stackAmount, duration);
independentStacks.Add(addition);
independentStacks.Sort();
return addition;
}
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>, ICloneable<IndependentStackUnit>
{
public int stackAmount;
public float duration;
public float remainingTime;
public Dictionary<string, float> parameters;
public bool IsInfinite => duration < 0;
public float RemainingPercentage => IsInfinite ? 1f : remainingTime / duration;
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);
}
public IndependentStackUnit Clone()
{
IndependentStackUnit clone = new IndependentStackUnit(stackAmount, duration);
clone.remainingTime = remainingTime;
foreach (var param in parameters)
{
clone.parameters[param.Key] = param.Value;
}
return clone;
}
}
}
}
}