using System.Collections.Generic; using UnityEngine; using BaseGames.Core; namespace BaseGames.Enemies.Abilities { /// /// 能力配置包(架构 07_EnemyModule §8.2)。 /// 一个能力 = 一组攻击段 + 公共参数(冷却/中断规则)。 /// 预警不在此配置:预警的载体是动画 clip 本身(姿态在动画里,音效与特效挂动画事件)。 /// 由对应 EnemyAbilityBase 子类组件读取并执行。 /// [CreateAssetMenu(menuName = "BaseGames/Enemies/Enemy Ability", fileName = "ABL_")] public class EnemyAbilitySO : ScriptableObject, IValidatable { [Header("标识")] [Tooltip("能力唯一 id(全小写英文 + 下划线,如 \"melee_combo\" / \"blink_strike\")。" + "AI 图与选招器通过它引用本能力")] public string abilityId = "ability_id"; [TextArea(1, 4)] [Tooltip("设计备注(仅供编辑器参考,不影响运行)")] public string designNote; [Header("攻击序列")] public EnemyAttackSO[] attackSequence; [Header("冷却(秒,从能力执行结束开始计)")] [Min(0f)] public float cooldown = 1.5f; [Header("中断规则")] [Tooltip("受击时是否打断能力(false=能力具霸体)")] public bool interruptOnHurt = true; [Tooltip("Stagger 时是否打断(一般为 true)")] public bool interruptOnStagger = true; [Header("调度提示(供 AI 选择参考,不强制)")] [Min(0f)] public float preferredMinRange = 0f; [Min(0f)] public float preferredMaxRange = 5f; public bool requiresLineOfSight = true; public bool requiresGrounded = true; [Header("互斥组与调度优先级")] [Tooltip("互斥组名:同组能力只能有一个同时执行,执行时自动中断同组其他能力;为空 = 无互斥")] public string exclusionGroup = ""; [Tooltip("AI 调度优先级(值越高越优先被选择,冷却就绪时对比)")] [Min(0)] public int priority = 0; [Header("选招(攻击选择器用)")] [Tooltip("能力调度分类;攻击选择器只从 Attack 类里选招")] public AbilityCategory category = AbilityCategory.None; [Tooltip("WeightedRandom 模式下的相对权重(越大越易被选)")] [Min(0f)] public float weight = 1f; [Header("攻击触发范围(招式自管,圆形)")] [Tooltip("触发半径(m);category==Attack 时必须 > 0,否则永远够不着(Awake 报错)")] [Min(0f)] public float rangeRadius = 0f; [Tooltip("范围圆心相对敌人的偏移(m),X 随朝向翻转")] public Vector2 rangeOffset = Vector2.zero; /// SOValidationRunner 自动扫描调用:校验 Attack 类招式必须配置有效射程。 public IEnumerable Validate() { if (category == AbilityCategory.Attack && rangeRadius <= 0f) yield return ValidationResult.Error( $"能力 \"{abilityId}\" category=Attack 但 rangeRadius<=0,攻击选择器永远选不中该招式,请补齐 rangeRadius。"); } } }