using System; using System.Collections.Generic; using System.Linq; using Continentis.MainGame.Card; using Continentis.MainGame.Character; using Continentis.MainGame.UI; using SoftCircuits.Collections; using SLSFramework.General; using SLSFramework.UModAssistance; using UnityEngine; using UnityEngine.Events; namespace Continentis.MainGame { public partial class BuffBase { public abstract class BuffSubmodule : SubmoduleBase> { public BuffBase buff; protected BuffSubmodule(BuffBase buff) : base(buff) { this.buff = buff; } } public class ContentSubmodule : BuffSubmodule { public string modClassName; public string displayName; public string originalFunctionText; public string interpretedFunctionText; public Dictionary> parameterGetters; /// /// 自动根据Buff类名生成显示名称和功能描述文本的Key并本地化。 /// /// 所属Buff实例。 /// 是否本地化功能描述文本,默认为true,设为false说明此Buff具有不止一条本地化文本,需要切换。 public ContentSubmodule(BuffBase buff, bool willLocalizeFuncText = true) : base(buff) { modClassName = ModManager.GetModClassName(buff.GetType()); this.displayName = ("Buff_" + modClassName + "_DisplayName").Localize(); if (willLocalizeFuncText) { this.originalFunctionText = ("Buff_" + modClassName + "_FunctionText").Localize(); this.interpretedFunctionText = this.originalFunctionText; } parameterGetters = new Dictionary>(); } public ContentSubmodule(BuffBase buff, string displayNameKey, string originalFunctionTextKey) : base(buff) { this.displayName = displayNameKey.Localize(); this.originalFunctionText = originalFunctionTextKey.Localize(); this.interpretedFunctionText = this.originalFunctionText; parameterGetters = new Dictionary>(); } public ContentSubmodule SetParameterGetter(Dictionary> getters) { parameterGetters = getters; return this; } public ContentSubmodule AddParameterGetter(string parameterName, Func getter) { parameterGetters[parameterName] = getter; return this; } } public class IconSubmodule : BuffSubmodule { public string iconID; public Sprite icon; public List synchronizedParameters; public HUD_CharacterBuffIcon buffIcon; public IconSubmodule(BuffBase buff, string iconID = "") : base(buff) { if (string.IsNullOrEmpty(iconID)) { this.iconID = "BuffIcon_" + ModManager.GetModClassName(buff.GetType()); } else { this.iconID = iconID; } Texture2D tex = ModManager.GetAsset(this.iconID); if (tex != null) { this.icon = SpriteExtension.Create(tex); } else { this.icon = MainGameManager.Instance.basePrefabs.defaultBuffIcon; } 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() { buffIcon?.UpdateIcon(); } public void Remove() { //buffIcon?.RemoveIcon(); } } public class EventSubmodule : BuffSubmodule { public OrderedDictionary onCombatStart; //战斗开始时 public OrderedDictionary onCombatEnd; //战斗结束时 public OrderedDictionary onRoundStart; //每回合开始时 public OrderedDictionary onRoundEnd; //每回合结束时 public OrderedDictionary onActionStart; //每次行动开始时 public OrderedDictionary onActionEnd; //每次行动结束时 public OrderedDictionary>> onOtherBuffApplied; //Buff被添加时,参数为被添加的Buff实例 public OrderedDictionary>> onOtherBuffFirstApplied; //Buff被新添加时,参数为被添加的Buff实例 public OrderedDictionary>> onOtherBuffRemoved; //Buff被移除后,参数为被移除的Buff实例 public OrderedDictionary> onOpponentDecideAction; //对手AI决定行动时,参数为对手,和原定的目标角色 public OrderedDictionary> onDealAttack; //造成伤害后,参数为伤害结果 public OrderedDictionary> onGetAttacked; //被攻击后,参数为伤害结果 public OrderedDictionary> onDrawCard; //抽到卡牌时 public OrderedDictionary>> onBeforePlayCard; //使用卡牌前,参数为目标列表 public OrderedDictionary>> onAfterPlayCard; //使用卡牌后,参数为目标列表 public OrderedDictionary> onDiscardCard; //卡牌被弃牌时 public OrderedDictionary> onExhaustCard; //卡牌被消耗时 public EventSubmodule(BuffBase buff) : base(buff) { onCombatStart = new OrderedDictionary(); onCombatEnd = new OrderedDictionary(); onRoundStart = new OrderedDictionary(); onRoundEnd = new OrderedDictionary(); onActionStart = new OrderedDictionary(); onActionEnd = new OrderedDictionary(); onOtherBuffApplied = new OrderedDictionary>>(); onOtherBuffFirstApplied = new OrderedDictionary>>(); onOtherBuffRemoved = new OrderedDictionary>>(); onDealAttack = new OrderedDictionary>(); onGetAttacked = new OrderedDictionary>(); onOpponentDecideAction = new OrderedDictionary>(); onDrawCard = new OrderedDictionary>(); onBeforePlayCard = new OrderedDictionary>>(); onAfterPlayCard = new OrderedDictionary>>(); onDiscardCard = new OrderedDictionary>(); onExhaustCard = new OrderedDictionary>(); } } public class CountSubmodule : BuffSubmodule { public int maximumCount; public int remainingCount; public bool isInfinite => maximumCount < 0; public float remainingPercentage => (float)remainingCount / maximumCount; public UnityAction onCountChanged; /// /// maximumCount为负数表示无限持续时间。 /// public CountSubmodule(BuffBase 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(); } } /// /// 刷新剩余时间至初始值。 /// public void Refresh() { if (isInfinite) { return; } remainingCount = maximumCount; onCountChanged?.Invoke(remainingCount); } /// /// 覆盖(可选保留更大的duration)并刷新剩余时间。 /// public void Refresh(int overrideDuration, bool keepMaximal = true) { if (isInfinite) { return; } maximumCount = keepMaximal ? Mathf.Max(maximumCount, overrideDuration) : overrideDuration; remainingCount = maximumCount; onCountChanged?.Invoke(remainingCount); } /// /// 增加持续时间和剩余时间。 /// public void AddCount(int maxCount) { if (isInfinite) { return; } maximumCount += maxCount; remainingCount += maxCount; onCountChanged?.Invoke(remainingCount); } /// /// 仅增加剩余时间,不改变总持续时间。 /// 如果增加后剩余时间超过总持续时间,则剩余时间等于总持续时间。 /// public void AddRemainingCount(int count) { if (isInfinite) { return; } remainingCount += count; remainingCount = Mathf.Min(remainingCount, maximumCount); onCountChanged?.Invoke(remainingCount); } /// /// 选择更高的持续时间和剩余时间。 /// public void PickHigherCount(CountSubmodule other) { if (isInfinite) { return; } maximumCount = Mathf.Max(maximumCount, other.maximumCount); remainingCount = Mathf.Max(remainingCount, other.remainingCount); } public void PickHigherCount(int maximumCount, int remainingCount) { if (isInfinite) { return; } this.maximumCount = Mathf.Max(this.maximumCount, maximumCount); this.remainingCount = Mathf.Max(this.remainingCount, remainingCount); } } /// /// Buff叠加模块,叠加层数统一。 /// 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 buff, int initialStackAmount = 1, bool isIntegerRange = false) : base(buff) { this.willRemoveOnZero = true; this.isIntegerRange = isIntegerRange; this.stackAmount = initialStackAmount; this.stackUpperLimit = -1; } public UnitedStackSubmodule(BuffBase 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(); } } if(buff is CharacterBuffBase characterBuff) { characterBuff.iconSubmodule?.Update(); } } public void ClearAllStacks() { stackAmount = 0; if (willRemoveOnZero) { buff.Remove(); } } } /// /// Buff独立叠加模块,每一层的持续时间和层数可以不同。 /// public class IndependentStackSubmodule : BuffSubmodule { public bool willRemoveOnZero; public List independentStacks; public int totalStackAmount; public IndependentStackSubmodule(BuffBase buff, bool willRemoveOnZero) : base(buff) { this.willRemoveOnZero = willRemoveOnZero; independentStacks = new List(); totalStackAmount = 0; } public void Update() { independentStacks.ForEach(x => x.remainingTime--); independentStacks.RemoveAll(x => !x.IsInfinite && x.remainingTime <= 0); totalStackAmount = independentStacks.Sum(x => x.stackAmount); if (willRemoveOnZero && totalStackAmount <= 0) { buff.Remove(); } } public IndependentStackUnit AddStack(int stackAmount, int 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 { public int stackAmount; public int duration; public int remainingTime; public Dictionary parameters; public bool IsInfinite => duration < 0; public IndependentStackUnit(int stackAmount, int duration) { this.stackAmount = stackAmount; this.duration = duration; this.remainingTime = duration; this.parameters = new Dictionary(); } public int CompareTo(IndependentStackUnit other) { return remainingTime.CompareTo(other.remainingTime); } } } } }