lcy
4 天以前 2dd1841d03a730d3d369092c2a3ad656cee4bf64
Main/System/Battle/Skill/SkillBase.cs
@@ -1,774 +1,349 @@
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using Spine;
using System.Linq;
using System;
public class SkillBase
// SkillBase:技能运行时基类。
// 本类使用 partial 拆分为多个文件,按职责分组:
//   SkillBase.cs             字段、构造、公共入口(Cast/Run/OnSkillStart/各 Frame 回调 等)
//   SkillBase.Cast.cs        施法阶段:移动、动画、残影、高亮、攻击回合结束
//   SkillBase.Hit.cs         命中阶段:OnHit 分发到主目标 / 溅射目标 / 命中提示
//   SkillBase.SubSkill.cs    前置内嵌子技能的收集与投递
//   SkillBase.Death.cs       死亡包与掉落/经验分配
//   SkillBase.Buff.cs        Buff 包(HB428/HB429)的收集与分发
//   SkillBase.Finish.cs      完成判定与强制结束
public partial class SkillBase
{
   const float moveTime = 0.5f;
    // ===== 常量 =====
    const float moveTime = 0.5f;
   protected SkillEffect skillEffect;
    private static readonly Color colorGreen = new Color(33f / 255f,
                                                        133f / 255f,
                                                        6f / 255f);
    private static readonly Color colorBlue = new Color(40f / 255f,
                                                        87f / 255f,
                                                        189f / 255f);
   protected HB427_tagSCUseSkill tagUseSkillAttack;
    // ===== 核心引用 =====
    public HB427_tagSCUseSkill tagUseSkillAttack;
    public SkillConfig skillConfig;
    public SkillSkinConfig skillSkinConfig;
    public BattleObject caster = null; // 施法者
    protected BattleField battleField = null; // 战场
    protected RectTransform targetNode = null; // 目标节点
    protected List<GameNetPackBasic> packList;
   public SkillConfig skillConfig;
    // ===== 命中效果 =====
    protected SkillEffect skillEffect;
   protected bool isFinished = false;
    // ===== 子技能/子动作等待列表 =====
    protected List<RecordAction> currentWaitingSkill = new List<RecordAction>();
   protected BattleField battleField = null; // 战场
    // ===== 死亡相关临时数据 =====
    protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>();
    protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>();
    private Dictionary<int, BattleDrops> tempDropList = new Dictionary<int, BattleDrops>();
    private Dictionary<int, BattleDeadPack> tempDeadPackList = new Dictionary<int, BattleDeadPack>();
   protected RectTransform targetNode = null; // 目标节点
    // ===== Buff 相关包集合,支持 HB428(刷新) 和 HB429(删除) =====
    protected List<GameNetPackBasic> buffPackCollections = new List<GameNetPackBasic>();
   protected BattleObject caster = null; // 施法者
    // ===== 生命周期状态(4 个并行里程碑位,合并到同一 Flags 字段) =====
    //   Started        : 已进入施法阶段(OnSkillStart 调用后)
    //   MoveCompleted  : 位移已收尾(OnAllAttackMoveFinished)
    //   MotionCompleted: 技能动画已播放完(OnFinalFrameEnd)
    //   Finished       : 包列表已处理完(OnSkillFinished / ForceFinished 结尾)
    //   4 个里程碑相互独立,非线性阶段,不能用单一 state 表达。
    [System.Flags]
    protected enum SkillStateFlags
    {
        None            = 0,
        Started         = 1 << 0,
        MoveCompleted   = 1 << 1,
        MotionCompleted = 1 << 2,
        Finished        = 1 << 3,
    }
   protected List<GameNetPackBasic> packList;
    private SkillStateFlags _stateFlags = SkillStateFlags.None;
   protected SkillRecordAction otherSkillAction;
    /// <summary>当前技能状态位(只读,调试用)。</summary>
    protected SkillStateFlags StateFlags => _stateFlags;
   protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>();
#if UNITY_EDITOR
    /// <summary>供外部调试/诊断打印用,非编辑器下不编译。</summary>
    public string StateFlagsForDebug => _stateFlags.ToString();
#endif
   protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>();
    /// <summary>是否已进入施法阶段(OnSkillStart 调用后为 true)。</summary>
    public bool isPlay
    {
        get => (_stateFlags & SkillStateFlags.Started) != 0;
        set => SetFlag(SkillStateFlags.Started, value);
    }
   protected bool moveFinished = false;
    /// <summary>包列表是否已全部处理完。</summary>
    protected bool isFinished
    {
        get => (_stateFlags & SkillStateFlags.Finished) != 0;
        set => SetFlag(SkillStateFlags.Finished, value);
    }
    public int fromSkillId;
    /// <summary>位移是否已收尾。</summary>
    protected bool moveFinished
    {
        get => (_stateFlags & SkillStateFlags.MoveCompleted) != 0;
        set => SetFlag(SkillStateFlags.MoveCompleted, value);
    }
   public bool isPlay = false;
    /// <summary>技能动画是否已播放完。</summary>
    protected bool isMotionCompleted
    {
        get => (_stateFlags & SkillStateFlags.MotionCompleted) != 0;
        set => SetFlag(SkillStateFlags.MotionCompleted, value);
    }
    private void SetFlag(SkillStateFlags flag, bool value)
    {
#if UNITY_EDITOR
        //  记录状态变更:卡死/卡活的排查利器。
        //  编辑器下只在值真正发生改变时打印,避免刷屏。
        bool oldValue = (_stateFlags & flag) != 0;
        if (oldValue != value)
        {
            int skillId = skillConfig != null ? skillConfig.SkillID : 0;
            ulong casterId = tagUseSkillAttack != null ? tagUseSkillAttack.ObjID : 0UL;
            BattleDebug.LogError(
                $"SkillBase.StateFlags 变更:skillId={skillId} caster={casterId} " +
                $"{flag}: {oldValue} -> {value}  (before={_stateFlags})");
        }
#endif
        if (value) _stateFlags |= flag;
        else       _stateFlags &= ~flag;
    }
    // ===== 父子关系 =====
    public SkillBase fromSkill;
    //  父RecordAction(SkillRecordAction),用于子技能建立父子关系
    protected SkillRecordAction ownRecordAction;
    // ===== 移动速度(残影加速时会改变) =====
    private float MoveSpeed = 750f;
#if UNITY_EDITOR
    public static Dictionary<string, string> changeListDict = new Dictionary<string, string>();
#endif
    // 构造函数:初始化技能基础数据
    public SkillBase(BattleObject _caster, SkillConfig _skillCfg, HB427_tagSCUseSkill vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null)
   {
      caster = _caster;
      if (null == caster)
      {
         throw new Exception("SkillBase caster is null ");
      }
      skillConfig = _skillCfg;
      tagUseSkillAttack = vNetData;
      battleField = _battleField;
      packList = _packList;
    {
        caster = _caster;
        skillConfig = _skillCfg;
        tagUseSkillAttack = vNetData;
        battleField = _battleField;
        packList = _packList;
      // Debug.LogError("start a skill id " + skillConfig.SkillID + " caster " + caster.teamHero.heroId + " pos " + caster.teamHero.positionNum + " camp " + caster.Camp);
        if (_caster is HeroBattleObject heroBattleObject)
        {
            skillSkinConfig = skillConfig.GetSkillSkinConfig(heroBattleObject.teamHero.SkinID);
   }
            if (null == skillSkinConfig)
            {
                Debug.LogError("找不到技能皮肤表 " + "skillId: " + skillConfig.SkillID + " skinId: " + heroBattleObject.teamHero.SkinID);
            }
        }
        else
        {
            skillSkinConfig = skillConfig.GetOriginSkinConfig();
        }
   public virtual void Run()
   {
      if (null != skillEffect)
      {
         if (skillEffect.IsFinished())
         {
            skillEffect = null;
            OnSkillFinished();
         }
         else
         {
            skillEffect.Run();
         }
         return;
      }
      if (otherSkillAction != null)
      {
         if (otherSkillAction.IsFinished())
         {
            otherSkillAction = null;
            OnSkillFinished();
         }
         else
         {
            if (moveFinished)
            {
               otherSkillAction.Run();
            }
         }
         return;
      }
   }
        // 注册正在释放的技能
        if (battleField != null && caster != null)
        {
            battleField.AddCastingSkill(caster.ObjID, this);
        }
   // 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身)
   // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类)
   public virtual void Cast()
   {
      // Debug.LogError("Cast skill " + skillConfig.SkillID + " cast position " + skillConfig.CastPosition + " cast mode " + skillConfig.castMode);
      string guid = battleField.guid;
      TeamHero teamHero = caster.teamHero;
      EventBroadcast.Instance.Broadcast<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, guid, skillConfig, teamHero);
        SafetyCheck();
    }
      //   高亮所有本次技能相关的目标
      HighLightAllTargets();
    public virtual void AfterAddToQueue()
    {
      //   距离配成负数要转身 TurnBack
      switch (skillConfig.castMode)
      {
         case SkillCastMode.Self:
            CastImpl(OnAttackFinish);
            break;
         case SkillCastMode.Enemy:
            CastToEnemy();
            break;
         case SkillCastMode.Target:
            CastToTarget();
            break;
         case SkillCastMode.Allies:
            CastToAllies();
            break;
         case SkillCastMode.DashCast:
            DashCast(OnAttackFinish);
            break;
         default:
            Debug.LogError("强制结束技能 暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition);
            ForceFinished();
            break;
      }
    }
   }
    //  设置父RecordAction
    public void SetOwnRecordAction(SkillRecordAction recordAction)
    {
        ownRecordAction = recordAction;
    }
   //   冲撞攻击
   protected void DashCast(Action _onComplete)
   {
      Debug.LogError("DashCast 还没实现");
      ForceFinished();
      //   YYL TODO
    private void PinrtHB427Hp()
    {
#if UNITY_EDITOR
        string skillDetail = "SkillCaster : " + tagUseSkillAttack.ObjID + " -> cast SkillID: " + skillConfig.SkillID + "\n";
      // var entry = caster.motionBase.PlayAnimation(skillConfig.GetMotionName(), false);
      // float animationTime = entry.AnimationTime;
        skillDetail += "------------------ HurtList ------------------\n";
        for (int i = 0; i < tagUseSkillAttack.HurtCount; i++)
        {
            var Hurt = tagUseSkillAttack.HurtList[i];
            BattleObject battleObject = caster.battleField.battleObjMgr.GetBattleObject((int)Hurt.ObjID);
      // int mainTargetPosNum = BattleUtility.GetMainTargetPositionNum(caster, tagUseSkillAttack.HurtList.ToList(), skillConfig);
            string targetName = battleObject != null ? battleObject.GetName() : "Unknown";
            long hurtHp = GeneralDefine.GetFactValue(Hurt.HurtHP, Hurt.HurtHPEx);
            long curHp = GeneralDefine.GetFactValue(Hurt.CurHP, Hurt.CurHPEx);
      // BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
            skillDetail += $"  [{i}] Target: {targetName} (ObjID:{Hurt.ObjID})\n";
            skillDetail += $"      HurtHP: {hurtHp}\n";
            skillDetail += $"      CurHP: {curHp}\n";
            skillDetail += $"      SuckHP: {Hurt.SuckHP}\n";
            skillDetail += $"      BounceHP: {Hurt.BounceHP}\n";
            skillDetail += $"      AttackTypes: {Hurt.AttackTypes}\n";
      // RectTransform targetTrans = battleField.GetTeamNode(battleCamp, mainTargetPosNum);
            if (Hurt.HurtListEx != null && Hurt.HurtListEx.Length > 0)
            {
                skillDetail += $"      HurtListEx ({Hurt.HurtListEx.Length}):\n";
                for (int j = 0; j < Hurt.HurtListEx.Length; j++)
                {
                    var hurtEx = Hurt.HurtListEx[j];
                    long hurtExHp = GeneralDefine.GetFactValue(hurtEx.HurtHP, hurtEx.HurtHPEx);
                    long curExHp = GeneralDefine.GetFactValue(hurtEx.CurHP, hurtEx.CurHPEx);
      // var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, targetTrans, new Vector2(skillConfig.CastDistance, 0), animationTime * 0.9f, () =>
      // {
      //    caster.motionBase.PlayAnimation(MotionName.idle, true);
      //    _onComplete?.Invoke();
      // });
      // battleField.battleTweenMgr.OnPlayTween(tweener);
   }
                    skillDetail += $"        [{j}] ObjID:{hurtEx.ObjID} HurtHP:{hurtExHp} CurHP:{curExHp} SuckHP:{hurtEx.SuckHP} AttackTypes:{hurtEx.AttackTypes}\n";
                }
            }
        }
   protected void MoveToTarget(RectTransform target, Vector2 offset, Action _onComplete = null, float speed = 500f)
   {
      //   原地释放
      if (skillConfig.CastDistance >= 9999)
      {
         _onComplete?.Invoke();
         return;
      }
        skillDetail += "------------------ HurtListEx ------------------\n";
        if (tagUseSkillAttack.HurtListEx != null)
        {
            for (int i = 0; i < tagUseSkillAttack.HurtListEx.Length; i++)
            {
                var HurtEx = tagUseSkillAttack.HurtListEx[i];
                BattleObject battleObject = caster.battleField.battleObjMgr.GetBattleObject((int)HurtEx.ObjID);
      caster.motionBase.PlayAnimation(MotionName.run, true);
      var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, target, offset, () =>
      {
         caster.motionBase.PlayAnimation(MotionName.idle, true);
         _onComplete?.Invoke();
      }, speed);
      battleField.battleTweenMgr.OnPlayTween(tweener);
                string targetName = battleObject != null ? battleObject.GetName() : "Unknown";
                long hurtHp = GeneralDefine.GetFactValue(HurtEx.HurtHP, HurtEx.HurtHPEx);
                long curHp = GeneralDefine.GetFactValue(HurtEx.CurHP, HurtEx.CurHPEx);
      // Debug.LogError("move to tarrget " + target.name + " offset " + offset + " speed " + speed + " time " + tweener.Duration());
   }
                skillDetail += $"  [{i}] Target: {targetName} (ObjID:{HurtEx.ObjID})\n";
                skillDetail += $"      HurtHP: {hurtHp}\n";
                skillDetail += $"      CurHP: {curHp}\n";
                skillDetail += $"      SuckHP: {HurtEx.SuckHP}\n";
                skillDetail += $"      AttackTypes: {HurtEx.AttackTypes}\n";
            }
        }
   protected void TurnBack(Action _onComplete, float forward)
   {
      if (skillConfig.CastDistance < 0)
      {
         //   转身
         Vector3 scale = caster.heroGo.transform.localScale;
         scale.x = Mathf.Abs(scale.x) * forward;
         caster.heroGo.transform.localScale = scale;
      }
      _onComplete?.Invoke();
   }
        skillDetail += "------------------ END ------------------\n";
   protected void CastToEnemy()
   {
        if (changeListDict.ContainsKey(caster.battleField.guid))
        {
            string origin = changeListDict[caster.battleField.guid];
            origin += skillDetail;
            changeListDict[caster.battleField.guid] = origin;
      RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig);
        }
        else
            changeListDict.Add(caster.battleField.guid, skillDetail);
      MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), () =>
      {
         //   到位置转身(不一定非要转身 但是流程要写)
         TurnBack(() =>
         {
            //   到达目标位置
            CastImpl(() =>
            {
               TurnBack(
                  () =>
                  {
                     //   回到原来的位置
                     MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero,
                        OnAttackFinish, 750F);
                  }
               , -1f);
            });
         }, -1f);
      });
   }
        Debug.LogError("skillDetail : " + skillDetail);
#endif
    }
    private void SafetyCheck()
    {
#if UNITY_EDITOR
        if (Launch.Instance.isOpenSkillLogFile)
        {
            PinrtHB427Hp();
        }
#endif
        bool safety = caster != null
                        && skillConfig != null
                        && tagUseSkillAttack != null
                        && battleField != null;
   protected void CastToTarget()
   {
      // 目标是敌方主目标
      if (tagUseSkillAttack.HurtCount <= 0)
      {
         Debug.LogError("技能攻击包没有目标 HurtCount <= 0");
         OnSkillFinished();
         return;
      }
      int mainTargetPosNum = BattleUtility.GetMainTargetPositionNum(caster, tagUseSkillAttack.HurtList.ToList(), skillConfig);
        if (!safety)
        {
            Debug.LogError("SkillBase SafetyCheck failed! Caster or SkillConfig or TagUseSkillAttack or BattleField is null, or Caster is dead.");
            ForceFinished();
        }
    }
      BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
    // 技能运行主逻辑:处理技能效果和其他技能动作
    public virtual void Run()
    {
        if (skillEffect != null)
        {
            if (skillEffect.IsFinished())
            {
                skillEffect = null;
                OnSkillFinished();
            }
            else
            {
                skillEffect.Run();
            }
            return;
        }
    }
      RectTransform targetTrans = battleField.GetTeamNode(battleCamp, mainTargetPosNum);
    // 技能开始回调:处理死亡、子技能、技能效果初始化
    public void OnSkillStart()
    {
        if (isPlay)
        {
            Debug.LogError(" play twice OnSkillStart skillId :" + skillConfig.SkillID);
            return;
        }
      MoveToTarget(targetTrans, new Vector2(skillConfig.CastDistance, 0), () =>
      {
         //   到位置转身(不一定非要转身 但是流程要写)
         TurnBack(() =>
         {
            //   到达目标位置
            CastImpl(() =>
            {
               TurnBack(
                  () =>
                  {
                     RectTransform rectTransform = battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum);
                     //   回到原来的位置
                     MoveToTarget(rectTransform, Vector2.zero, OnAttackFinish, 750F);
                  }
               , -1f);
            });
         }, -1f);
      });
   }
        //  先把死亡包收集了
        HandleDead();
   protected virtual void OnAllAttackMoveFinished()
   {
      moveFinished = true;
      List<BattleObject> allList = battleField.battleObjMgr.allBattleObjDict.Values.ToList<BattleObject>();
      for (int i = 0; i < allList.Count; i++)
      {
         BattleObject bo = allList[i];
         bo.layerMgr.SetFront();
         // bo.heroRectTrans.SetParent(battleField.GetTeamNode(bo.Camp, bo.teamHero.positionNum), true);
         bo.heroInfoBar.SetActive(true);
      }
      battleField.battleRootNode.skillMaskNode.SetActive(false);
      // Debug.LogError("OnAllAttackMoveFinished skill " + skillConfig.SkillID + " cast position " + skillConfig.CastPosition + " cast mode " + skillConfig.castMode);
   }
        //  再处理 内嵌技能
        ProcessSubSkill();
   protected void CastToAllies()
   {
      RectTransform target = battleField.GetTeamNode(caster.Camp, skillConfig);
        skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, skillSkinConfig, tagUseSkillAttack);
        skillEffect.Play(OnHitTargets);
      MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), () =>
      {
         //   到位置转身(不一定非要转身 但是流程要写)
         TurnBack(() =>
         {
            //   到达目标位置
            CastImpl(() =>
            {
               TurnBack(
                  () =>
                  {
                     //   回到原来的位置
                     MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum),
                        Vector2.zero, OnAttackFinish, 750F);
                  }
               , -1f);
            });
         }, -1f);
      });
   }
   protected void OnAttackFinish()
   {
      TurnBack(null, 1f);
      OnAllAttackMoveFinished();
      caster.motionBase.PlayAnimation(MotionName.idle, true);
   }
        isPlay = true;
    }
    // ===== 技能节拍回调 =====
   //   承载技能大部分的逻辑
   protected TrackEntry CastImpl(Action onComplete = null)
   {
      // 播放施法动作
      //   onComplete是指施法动作播放完的回调 不代表是技能结束
      //   具体技能结束的时间应该看技能对应的逻辑
      //   这里只提供6个动作相关的函数
      // OnSkillStart 动作第一帧
      // OnStartSkillFrameEnd 前摇结束
      // OnMiddleFrameStart 中摇开始
      // OnMiddleFrameEnd 中摇结束
      // OnFinalFrameStart 后摇开始
      // OnFinalFrameEnd 后摇结束
    // 技能前摇结束回调
    public virtual void OnStartSkillFrameEnd() { }
      return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete);
   }
    // 技能中摇开始回调:通知技能效果处理中摇开始
    public virtual void OnMiddleFrameStart(int times)
    {
        skillEffect?.OnMiddleFrameStart(times); // 修复:添加空值检查
    }
   //   技能开始
   public void OnSkillStart()
   {
      skillEffect = SkillEffectFactory.CreateSkillEffect(
            caster,
            skillConfig,
            tagUseSkillAttack
         );
    // 技能中摇结束回调:通知技能效果处理中摇结束
    public virtual void OnMiddleFrameEnd(int times, int hitIndex)
    {
        skillEffect?.OnMiddleFrameEnd(times, hitIndex); // 修复:添加空值检查
    }
      skillEffect.Play(OnHitTargets);
      isPlay = true;
    // 技能后摇开始回调:通知技能效果处理后摇开始
    public virtual void OnFinalFrameStart()
    {
        skillEffect?.OnFinalFrameStart(); // 修复:添加空值检查
    }
   }
    // 技能后摇结束回调:通知技能效果处理后摇结束
    public virtual void OnFinalFrameEnd()
    {
        //  标记动画播放完成
        isMotionCompleted = true;
        BattleDebug.LogError($"SkillBase.OnFinalFrameEnd: 技能 {skillConfig?.SkillID} 动画播放完成");
   //   技能前摇帧结束
   public virtual void OnStartSkillFrameEnd()
   {
   }
   /// <summary>
   /// 中摇开始 times=第几次循环 从0开始
   /// </summary>
   /// <param name="times"></param>
   public virtual void OnMiddleFrameStart(int times)
   {
      skillEffect.OnMiddleFrameStart(times);
   }
   public virtual void OnMiddleFrameEnd(int times, int hitIndex)
   {
      skillEffect.OnMiddleFrameEnd(times, hitIndex);
   }
   /// <summary>
   /// 后摇开始
   /// </summary>
   public virtual void OnFinalFrameStart()
   {
      skillEffect.OnFinalFrameStart();
   }
   /// <summary>
   /// 后摇结束
   /// </summary>
   public virtual void OnFinalFrameEnd()
   {
      skillEffect.OnFinalFrameEnd();
      HandleDead();
   }
   protected void HighLightAllTargets()
   {
      if (skillConfig.FuncType != 2)
         return;
      // 高亮所有目标
      List<BattleObject> targetList = battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack);
      List<BattleObject> highlightList = new List<BattleObject>(targetList);
      highlightList.Add(caster);
      List<BattleObject> allList = battleField.battleObjMgr.allBattleObjDict.Values.ToList<BattleObject>();
      caster.heroInfoBar.SetActive(false);
      for (int i = 0; i < allList.Count; i++)
      {
         BattleObject bo = allList[i];
         if (highlightList.Contains(bo))
         {
            bo.layerMgr.SetFront();
            bo.heroInfoBar.SetActive(true);
            // bo.heroRectTrans.SetParent(battleField.battleRootNode.skillFrontNode, true);
         }
         else
         {
            bo.layerMgr.SetBack();
            // bo.heroRectTrans.SetParent(battleField.battleRootNode.skillBackNode, true);
         }
         if (targetList.Contains(bo))
         {
            bo.heroInfoBar.SetActive(true);
         }
         else
         {
            bo.heroInfoBar.SetActive(false);
         }
      }
      caster.layerMgr.SetSortingOrder(BattleConst.ActiveHeroActionSortingOrder);
      battleField.battleRootNode.skillMaskNode.SetActive(true);
      battleField.battleRootNode.SetSortingOrder();
      // caster.battleField.skillMask
      //   把这些BO全高亮 或者说把除了这些的都放在遮罩后面
      //   YYL TODO
   }
   //   命中目标后的回调 正常是以各技能的方式来处理的
   protected virtual void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList)
   {
      for (int i = 0; i < hitList.Count; i++)
      {
         HB427_tagSCUseSkill.tagSCUseSkillHurt hurt = hitList[i];
         BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
         if (target == null)
         {
            Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
            continue;
         }
         OnHitEachTarget(_hitIndex, target, hurt);
      }
   }
   protected virtual void OnHitEachTarget(int _hitIndex, BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt)
   {
      // 伤害分布 (万分比)
      // Debug.LogError("skillConfig.DamageDivide.Count " + skillConfig.DamageDivide.Length + " _hitIndex " + _hitIndex);
      int[] damageDivide = skillConfig.DamageDivide[_hitIndex];
      long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
      // 保证所有分配项加起来等于totalDamage,避免因整除导致的误差
      List<long> damageList = BattleUtility.DivideDamageToList(damageDivide, totalDamage);
      // public uint ObjID;
      // public uint AttackTypes;        // 飘血类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避
      // public uint HurtHP;        // 飘血值,求余亿部分
      // public uint HurtHPEx;        // 飘血值,整除亿部分
      // public uint CurHP;        // 更新剩余血量,求余亿部分
      // public uint CurHPEx;        // 更新剩余血量,整除亿部分
      // public uint SuckHP;        // 本次伤害转化的吸血量
      // public uint BounceHP;        // 本次伤害反弹的伤害量
      //   TODO YYL AttackTypes  要表现成什么样呢? 支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避
      target.Hurt(damageList, totalDamage, hurt, skillConfig);
      //   TODO YYL 这里是要做统一计算后再hurt跟suckhp还是怎样
      caster.SuckHp(hurt.SuckHP, skillConfig);//   吸血
      caster.HurtByReflect(hurt.BounceHP, skillConfig);// 反弹伤害
   }
   protected void HandleDead()
   {
      var deadPackList = BattleUtility.FindDeadPack(packList);
      int deadCount = deadPackList.Count;
      if (deadCount <= 0)
      {
         //   如果没死亡就不用管
         return;
      }
      CheckAfterDeadhPack();
      // 处理掉落包 提前distribute之后 PackManager才有掉落物 所以不跟assignexp一样distribute
      foreach (var _dropPack in dropPackList)
      {
         PackageRegedit.Distribute(_dropPack);
         packList.Remove(_dropPack);
      }
      // 获取掉落物品
      var dropPack = PackManager.Instance.GetSinglePack(PackType.DropItem);
      var itemDict = dropPack.GetAllItems();
      List<ItemModel> itemList = new List<ItemModel>(
         from item in itemDict.Values
         where item != null && item.isAuction
         select item);
      // 分配掉落和经验
      var dropAssign = AssignDrops(itemList, deadCount);
      var expAssign = AssignExp(expPackList, deadCount);
      // 构造 BattleDrops 并分配
      for (int i = 0; i < deadCount; i++)
      {
         BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject((int)deadPackList[i].ObjID);
         List<ItemModel> itemModelDrops = dropAssign[i];
         List<int> itemModelDropsIndexList = new List<int>(
            from item in itemModelDrops select item.gridIndex);
         BattleDrops battleDrops = new BattleDrops()
         {
            rectTransform = deadTarget.heroRectTrans,
            dropItemPackIndex = itemModelDropsIndexList,
            expDrops = expAssign[i]
         };
         deadTarget.PushDropItems(battleDrops);
      }
      // 分发死亡包
      battleField.OnObjsDead(new List<HB422_tagMCTurnFightObjDead>(deadPackList));
      foreach (var deadPack in deadPackList)
      {
         packList.Remove(deadPack);
      }
      deadPackList.Clear();
   }
   // 分配掉落
   protected List<List<ItemModel>> AssignDrops(List<ItemModel> itemList, int deadCount)
   {
      var dropAssign = new List<List<ItemModel>>(deadCount);
      for (int i = 0; i < deadCount; i++)
         dropAssign.Add(new List<ItemModel>());
      for (int i = 0; i < itemList.Count; i++)
         dropAssign[i % deadCount].Add(itemList[i]);
      return dropAssign;
   }
   // 分配经验:每个原始包都平均分配到每个死亡对象
   protected List<List<HB405_tagMCAddExp>> AssignExp(List<HB405_tagMCAddExp> expList, int deadCount)
   {
      var expAssign = new List<List<HB405_tagMCAddExp>>(deadCount);
      for (int i = 0; i < deadCount; i++)
         expAssign.Add(new List<HB405_tagMCAddExp>());
      foreach (var expPack in expList)
      {
         long totalExp = GeneralDefine.GetFactValue(expPack.Exp, expPack.ExpPoint);
         long avgExp = totalExp / deadCount;
         long remain = totalExp % deadCount;
         for (int i = 0; i < deadCount; i++)
         {
            long assignExp = avgExp + (i < remain ? 1 : 0);
            long expPoint = assignExp / 100000000;
            long exp = assignExp % 100000000;
            var newPack = new HB405_tagMCAddExp
            {
               Exp = (uint)exp,
               ExpPoint = (uint)expPoint,
               Source = expPack.Source // 保持原包来源
            };
            expAssign[i].Add(newPack);
         }
         packList.Remove(expPack);
      }
      return expAssign;
   }
   protected void CheckAfterDeadhPack()
   {
      List<int> removeIndexList = new List<int>();
      for (int i = 0; i < packList.Count; i++)
      {
         var pack = packList[i];
         //    复活基本都靠技能包
         if (pack is CustomHB426CombinePack)
         {
            var combinePack = pack as CustomHB426CombinePack;
            if (combinePack.startTag.Tag.StartsWith("Skill_"))
            {
               break; // 找到技能包就不需要再处理了
            }
         }
         else if (pack is H0704_tagRolePackRefresh)
         {
            var h0704Pack = pack as H0704_tagRolePackRefresh;
            if (h0704Pack.PackType == (byte)PackType.DropItem)
            {
               //   掉落的
               if (h0704Pack.IsBind == 1)
               {
                  //   掉落的物品
                  dropPackList.Add(h0704Pack);
                  removeIndexList.Add(i);
               }
               else if (h0704Pack.IsBind == 0)
               {
                  //   替换的
               }
            }
         }
         else if (pack is HB405_tagMCAddExp)
         {
            var h405Pack = pack as HB405_tagMCAddExp;
            //B4 05 获得经验 #tagMCAddExp 通知获得的经验,
            //可用于做经验获得表现 Source = 2 时为主线击杀怪物获得经验
            if (h405Pack.Source == 2)
            {
               expPackList.Add(h405Pack);
               removeIndexList.Add(i);
            }
         }
      }
      for (int i = removeIndexList.Count - 1; i >= 0; i--)
      {
         packList.RemoveAt(removeIndexList[i]);
      }
   }
   public virtual bool IsFinished()
   {
      if (!isPlay)
      {
         return false;
      }
      if (skillEffect != null)
      {
         if (!skillEffect.IsFinished())
         {
            return false;
         }
         else
         {
            skillEffect = null;
            OnSkillFinished();
            return false;
         }
      }
      if (otherSkillAction != null)
      {
         if (!otherSkillAction.IsFinished())
         {
            return false;
         }
         else
         {
            otherSkillAction = null;
            OnSkillFinished();
            return false;
         }
      }
      if (isFinished && moveFinished)
      {
         if (packList.Count > 0)
         {
            OnSkillFinished();
            return false;
         }
         return true;
      }
      else
      {
         return false;
      }
   }
   public virtual void ForceFinished()
   {
      skillEffect?.ForceFinished();
      if (otherSkillAction != null)
      {
         otherSkillAction.ForceFinish();
         otherSkillAction = null;
      }
      HandleDead();
      isFinished = true;
      moveFinished = true;
      isPlay = true;
      while (packList.Count > 0)
      {
         var pack = packList[0];
         packList.RemoveAt(0);
         if (pack is CustomHB426CombinePack combinePack)
         {
            if (combinePack.startTag.Tag.StartsWith("Skill_"))
            {
               otherSkillAction = combinePack.CreateSkillAction();
               otherSkillAction.fromSkillId = skillConfig.SkillID;
               //   强制结束其他技能
               otherSkillAction.ForceFinish();
               continue;
            }
         }
         else if (pack is CustomB421ActionPack actionPack)
         {
            actionPack.Distribute();
         }
         PackageRegedit.Distribute(pack);
      }
   }
   public void OnSkillFinished()
   {
      if (skillEffect != null)
      {
         if (!skillEffect.IsFinished())
         {
            return;
         }
         else
         {
            skillEffect = null;
            OnSkillFinished();
         }
      }
      if (otherSkillAction != null)
      {
         if (!otherSkillAction.IsFinished())
         {
            return;
         }
         else
         {
            otherSkillAction = null;
            OnSkillFinished();
         }
      }
      while (packList.Count > 0)
      {
         var pack = packList[0];
         packList.RemoveAt(0);
         if (pack is CustomHB426CombinePack)
         {
            var combinePack = pack as CustomHB426CombinePack;
            if (combinePack.startTag.Tag.StartsWith("Skill_"))
            {
               BattleDebug.LogError("other skill casting " + combinePack.startTag.Tag);
               otherSkillAction = combinePack.CreateSkillAction();
               otherSkillAction.fromSkillId = skillConfig.SkillID;
               return;
            }
         }
         else if (pack is CustomB421ActionPack actionPack)
         {
            actionPack.Distribute();
         }
         // Debug.LogError("Distribute pack " + pack.GetType().ToString());
         PackageRegedit.Distribute(pack);
      }
      isFinished = true;
   }
        skillEffect?.OnFinalFrameEnd(); // 修复:添加空值检查
    }
}