using System; using System.Collections.Generic; using System.Linq; using Continentis.MainGame.Character; using Continentis.MainGame.Equipment; using SLSFramework.General; using SLSFramework.UModAssistance; using UnityEngine; namespace Continentis.MainGame.Card { public abstract partial class CardLogicBase { [Header("Reference")] public CardInstance card; public CardData cardData => card.cardData; public CharacterBase user => card.user; public HashSet logicComponents { get; private set; } /// 生成卡牌逻辑实例。 public static CardLogicBase GenerateCardLogic(CardData data) { string typeID = ModManager.GetTypeID(data.modName, "Cards", data.categoryName, data.className); Type logicType = ModManager.GetType(typeID); if (logicType == null) { Debug.LogError($"Card class '{typeID}' not found in assemblies."); return null; } if (Activator.CreateInstance(logicType) is CardLogicBase cardLogic) return cardLogic; Debug.LogError($"Card class '{typeID}' not found or could not be instantiated."); return null; } public virtual void Initialize(CardInstance cardInstance) { card = cardInstance; logicComponents = new HashSet(); card.eventSubmodule.onTargeting += TargetingEffect; card.eventSubmodule.onUntargeting += UntargetingEffect; } public virtual void SetUpLogicComponents() { } public T AddLogicComponent() where T : CardLogicComponentBase, new() { if (logicComponents.Any(component => component is T)) { Debug.LogWarning($"Card {card.cardData.className} already has component of type {typeof(T)}, cannot add duplicate."); return null; } T component = new T(); component.Initialize(this); logicComponents.Add(component); return component; } public T LogicComponent() where T : CardLogicComponentBase { return logicComponents.OfType().FirstOrDefault(); } public virtual void ApplyAttributeChangesByCard() { } /// 卡牌出牌效果,返回一个 CommandGroup 供队列执行。 public virtual CommandGroup PlayEffect(List targetList) { return new CommandGroup(); } public virtual void AfterPlayEffect(List targetList) { } } #region Attributes public partial class CardLogicBase { /// 设置可变属性值。 public void SetVariableAttribute(string attributeName, int baseOffset, bool additive = false, int originalValue = 0) { card.SetVariableAttribute(attributeName, baseOffset, additive, originalValue); } /// 检查卡牌是否具有某属性。 public bool HasAttribute(string attributeName) => card.HasAttribute(attributeName); /// 获取卡牌的属性值。 public int GetAttribute(string attributeName, int defaultValue = 0) => card.GetAttribute(attributeName, defaultValue); public float GetRawAttribute(string attributeName, float defaultValue = 0) => card.GetRawAttribute(attributeName, defaultValue); /// 设置卡牌的属性值(int)。 public void SetAttribute(string attributeName, int value) => card.SetAttribute(attributeName, value); /// 设置卡牌的属性值(float)。 public void SetAttribute(string attributeName, float value) => card.SetAttribute(attributeName, value); /// 修改卡牌的属性值。 public void ModifyAttribute(string attributeName, int delta) => card.ModifyAttribute(attributeName, delta); } #endregion #region Command public partial class CardLogicBase { // ── 新 API:闭包工厂(推荐,Mod 制作者优先使用) ───────────────────── /// /// 对 targetList 中的每个目标调用工厂 lambda,生成的命令按 mainExecutionMode 组合。 /// protected CommandGroup ForEachTarget( List targetList, Func factory, ExecutionMode mainExecutionMode = ExecutionMode.Sequential) { var group = new CommandGroup(mainExecutionMode); foreach (CharacterBase target in targetList) { CharacterBase captured = target; group.AddCommand(factory(captured)); } return group; } /// /// 对 targetList 中的每个目标调用工厂 lambda,生成的 CommandGroup 按 mainExecutionMode 组合。 /// protected CommandGroup ForEachTarget( List targetList, Func factory, ExecutionMode mainExecutionMode = ExecutionMode.Sequential) { var group = new CommandGroup(mainExecutionMode); foreach (CharacterBase target in targetList) { CharacterBase captured = target; group.AddCommand(factory(captured)); } return group; } // ── 旧 API:模板 Clone 模式(保留供向后兼容,后续迁移完成后移除) ── /// /// 克隆命令模板列表,组合为单个并行 CommandGroup。 /// protected CommandGroup SingleCommandGroup(params CommandBase[] commands) { return SingleCommandGroup(ExecutionMode.Parallel, commands); } /// /// 克隆命令模板列表,按 executionMode 组合为单个 CommandGroup。 /// protected virtual CommandGroup SingleCommandGroup( ExecutionMode executionMode = ExecutionMode.Parallel, params CommandBase[] commands) { var group = new CommandGroup(executionMode); foreach (CommandBase template in commands) group.AddCommand(template.Clone()); return group; } /// /// 对目标列表中的每个目标克隆命令模板并注入 Target,生成嵌套 CommandGroup。 /// 新代码请改用 闭包工厂模式。 /// [Obsolete("请改用 ForEachTarget(targetList, target => ...) 闭包工厂模式。")] protected CommandGroup TargetListCommandGroup( List targetList, params CommandBase[] singleCommands) { return TemplateTargetGroup(targetList, ExecutionMode.Sequential, ExecutionMode.Parallel, singleCommands); } /// /// 对目标列表中的每个目标克隆命令模板并注入 Target,生成嵌套 CommandGroup。 /// 新代码请改用 闭包工厂模式。 /// [Obsolete("请改用 ForEachTarget(targetList, target => ...) 闭包工厂模式。")] protected virtual CommandGroup TargetListCommandGroup( List targetList, ExecutionMode mainExecutionMode = ExecutionMode.Sequential, ExecutionMode singleExecutionMode = ExecutionMode.Parallel, params CommandBase[] singleCommands) { return TemplateTargetGroup(targetList, mainExecutionMode, singleExecutionMode, singleCommands); } /// /// 模板 Clone 模式的底层实现,供旧代码向后兼容。 /// 克隆每条模板命令并向所有子命令的 selfContext 注入 Target。 /// protected virtual CommandGroup TemplateTargetGroup( List targetList, ExecutionMode mainExecutionMode = ExecutionMode.Sequential, ExecutionMode singleExecutionMode = ExecutionMode.Parallel, params CommandBase[] singleCommands) { var mainGroup = new CommandGroup(mainExecutionMode); foreach (CharacterBase target in targetList) { var singleGroup = new CommandGroup(singleExecutionMode); foreach (CommandBase template in singleCommands) { CommandBase clone = template.Clone(); // 收集所有子命令(含嵌套组内的命令)并注入 Target var allCommands = clone is CommandGroup group ? group.GetAllCommands(true) : new List { clone }; foreach (CommandBase cmd in allCommands) cmd.selfContext.Set(CommandContextKeys.Target, target); singleGroup.AddCommand(clone); } mainGroup.AddCommand(singleGroup); } return mainGroup; } } #endregion #region Attack public partial class CardLogicBase { /// 获取对指定目标的最终伤害值。 public virtual int GetTargetedFinalDamage(CharacterBase target, List elementalTags = null) { return GetFinalDamage(target, elementalTags, out _, out _, out _, out _); } /// 获取无目标时的最终伤害值。 public virtual int GetNoTargetFinalDamage(List elementalTags = null) { return GetFinalDamage(null, elementalTags, out _, out _, out _, out _); } protected virtual int GetFinalDamage( CharacterBase target, List elementalTags, out float baseDamageAfterOffset, out float elementalMultiplier, out float magicMultiplier, out float finalMultiplier) { bool haveTarget = target != null; elementalTags ??= card.GetElementalKeywords(); int physicsOffset = 0; if (card.HasKeyword("Physics") || card.HasKeyword("Slash") || card.HasKeyword("Prick") || card.HasKeyword("Strike")) physicsOffset = user.GetAttribute("PhysicsDamageDealtOffset"); int magicOffset = 0; if (card.HasKeyword("Magic") || card.HasKeyword("Arcane") || card.HasKeyword("Sorcery")) magicOffset = user.GetAttribute("MagicDamageDealtOffset"); elementalMultiplier = 1f; foreach (string element in elementalTags) { float targetGain = haveTarget ? target.GetRawAttribute(element + "DamageGainMultiplier", 1f) : 1f; elementalMultiplier *= user.GetRawAttribute(element + "DamageDealtMultiplier", 1f) * targetGain; } magicMultiplier = 1f; if (card.HasKeyword("Magic") || card.HasKeyword("Arcane") || card.HasKeyword("Sorcery")) { float targetGain = haveTarget ? target.GetRawAttribute("MagicDamageGainMultiplier", 1f) : 1f; magicMultiplier = user.GetRawAttribute("MagicDamageDealtMultiplier", 1f) * targetGain; } float targetFinalGain = haveTarget ? target.GetRawAttribute("FinalDamageGainMultiplier", 1f) : 1f; finalMultiplier = user.GetRawAttribute("FinalDamageDealtMultiplier", 1f) * targetFinalGain; baseDamageAfterOffset = card.attributeSubmodule.GetCurrentAttribute("Damage") + physicsOffset + magicOffset; float finalDamage = baseDamageAfterOffset * elementalMultiplier * magicMultiplier * finalMultiplier; return Mathf.RoundToInt(finalDamage); } } #endregion #region Buffs public partial class CardLogicBase { /// 创建一个角色战斗 Buff 实例(通过 ModManager 类型注册)。 public T CreateCharacterBuff(params object[] parameters) where T : CharacterCombatBuffBase { string buffTypeID = ModManager.GetTypeID(typeof(T)); if (string.IsNullOrEmpty(buffTypeID)) { Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}"); return null; } return ModManager.CreateInstance(buffTypeID, parameters); } public T CreateCharacterBuff(string buffTypeID, params object[] parameters) where T : CharacterCombatBuffBase { if (string.IsNullOrEmpty(buffTypeID)) { Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}"); return null; } return ModManager.CreateInstance(buffTypeID, parameters); } /// 创建一个卡牌战斗 Buff 实例(通过 ModManager 类型注册)。 public T CreateCardBuff(params object[] parameters) where T : CardBuffBase { string buffTypeID = ModManager.GetTypeID(typeof(T)); if (string.IsNullOrEmpty(buffTypeID)) { Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}"); return null; } return ModManager.CreateInstance(buffTypeID, parameters); } public T CreateCardBuff(string buffTypeID, params object[] parameters) where T : CardBuffBase { if (string.IsNullOrEmpty(buffTypeID)) { Debug.LogError($"Failed to get buff name for type {typeof(T).FullName}"); return null; } return ModManager.CreateInstance(buffTypeID, parameters); } } #endregion public abstract partial class CardLogicBase { /// 获取衍生卡牌数据(按索引)。 public CardData GetDerivativeCardData(int index) { return ModManager.GetData(cardData.derivativeCardDataRefs[index]); } /// 获取衍生卡牌数据(按名称)。 public CardData GetDerivativeCardData(string dataName) { if (cardData.derivativeCardDataRefs.Contains(dataName)) return ModManager.GetData(dataName); Debug.LogError($"Card {cardData.className} does not contain derivative card data '{dataName}'."); return null; } /// 选中目标时触发的效果(在逻辑组件的 Targeting 之前执行)。 public virtual void TargetingEffect(CharacterBase target) { } /// 取消选中目标时触发的效果(在逻辑组件的 Untargeting 之前执行)。 public virtual void UntargetingEffect() { } } /// 卡牌逻辑组件基类。 public abstract class CardLogicComponentBase { protected CardLogicBase mainLogic; protected CardInstance card => mainLogic.card; protected CharacterBase user => card.user; protected CombatTeam usingTeam => card.usingTeam; public virtual void Initialize(CardLogicBase card) { this.mainLogic = card; this.card.eventSubmodule.onTargeting += TargetingEffect; this.card.eventSubmodule.onUntargeting += UntargetingEffect; } protected virtual void TargetingEffect(CharacterBase target) { } protected virtual void UntargetingEffect() { } } }