| | |
| | | protected List<SkillRecordAction> otherSkillActionList = new List<SkillRecordAction>(); |
| | | protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>(); |
| | | protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>(); |
| | | |
| | | protected List<BattleDeadPack> endDeadPackList = new List<BattleDeadPack>(); |
| | | |
| | | protected bool moveFinished = false; |
| | | public SkillBase fromSkill; |
| | | public bool isPlay = false; |
| | |
| | | private float MoveSpeed = 750f; |
| | | |
| | | private Dictionary<int, BattleDrops> tempDropList = new Dictionary<int, BattleDrops>(); |
| | | private Dictionary<int, HB422_tagMCTurnFightObjDead> tempDeadPackList = new Dictionary<int, HB422_tagMCTurnFightObjDead>(); |
| | | private Dictionary<int, BattleDeadPack> tempDeadPackList = new Dictionary<int, BattleDeadPack>(); |
| | | |
| | | protected List<HB428_tagSCBuffRefresh> buffCollections = new List<HB428_tagSCBuffRefresh>(); |
| | | // Buff相关包集合,支持 HB428(刷新) 和 HB429(删除) |
| | | protected List<GameNetPackBasic> buffPackCollections = new List<GameNetPackBasic>(); |
| | | |
| | | |
| | | // 构造函数:初始化技能基础数据 |
| | | 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; |
| | | |
| | | // 注册正在释放的技能 |
| | | if (battleField != null && caster != null) |
| | | { |
| | | battleField.AddCastingSkill(caster.ObjID, this); |
| | | } |
| | | |
| | | SafetyCheck(); |
| | | #if UNITY_EDITOR |
| | |
| | | RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig); |
| | | ExecuteMoveAndCastSequence(target, () => |
| | | { |
| | | // ShadowIllutionCreate(true); |
| | | MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, () => |
| | | if (skillConfig.ClientTriggerTiming == 1) |
| | | { |
| | | // ShadowIllutionCreate(false); |
| | | OnAttackFinish(); |
| | | }, MoveSpeed); |
| | | } |
| | | else |
| | | { |
| | | // ShadowIllutionCreate(true); |
| | | MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, () => |
| | | { |
| | | // ShadowIllutionCreate(false); |
| | | OnAttackFinish(); |
| | | }, MoveSpeed); |
| | | } |
| | | }); |
| | | } |
| | | |
| | |
| | | RectTransform target = battleField.GetTeamNode(caster.Camp, skillConfig); |
| | | ExecuteMoveAndCastSequence(target, () => |
| | | { |
| | | // ShadowIllutionCreate(true); |
| | | MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, () => |
| | | if (skillConfig.ClientTriggerTiming == 1) |
| | | { |
| | | // ShadowIllutionCreate(false); |
| | | OnAttackFinish(); |
| | | }, MoveSpeed); |
| | | } |
| | | else |
| | | { |
| | | // ShadowIllutionCreate(true); |
| | | MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, () => |
| | | { |
| | | // ShadowIllutionCreate(false); |
| | | OnAttackFinish(); |
| | | }, MoveSpeed); |
| | | } |
| | | }); |
| | | } |
| | | |
| | |
| | | // 高亮所有相关目标:设置施法者和目标的显示层级 |
| | | protected void HighLightAllTargets() |
| | | { |
| | | caster.layerMgr.SetSortingOrder(BattleConst.ActiveHeroActionSortingOrder); |
| | | caster.layerMgr.SetSortingOrder(BattleConst.SkillMaskOrder + BattleConst.BattleActiveHeroOffset); |
| | | |
| | | if (skillConfig.FuncType != 2) |
| | | return; |
| | |
| | | battleField.battleRootNode.skillMaskNode.SetActive(true); |
| | | } |
| | | |
| | | protected long suckHp = 0; |
| | | |
| | | // 命中目标回调:处理所有被命中的目标(包括主目标、弹射目标、溅射目标) |
| | | protected virtual void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList) |
| | |
| | | // 造成伤害前先处理血量刷新包 |
| | | HandleRefreshHP(); |
| | | |
| | | suckHp = 0; |
| | | |
| | | // 统计吸血总量(主目标) |
| | | foreach (var hurt in hitList) |
| | | { |
| | | suckHp += hurt.SuckHP; |
| | | } |
| | | bool suckHp = true; |
| | | |
| | | // 处理主目标列表 |
| | | foreach (var hurt in hitList) |
| | |
| | | continue; |
| | | } |
| | | |
| | | OnHitEachTarget(_hitIndex, target, hurt); |
| | | OnHitEachTarget(_hitIndex, target, hurt, suckHp); |
| | | |
| | | suckHp = false; |
| | | |
| | | // 处理该目标的额外目标列表(如弹射伤害的平摊目标) |
| | | if (hurt.HurtListEx != null && hurt.HurtListEx.Length > 0) |
| | |
| | | } |
| | | |
| | | // 处理单个目标被命中:应用伤害和施法者效果 |
| | | protected virtual void OnHitEachTarget(int _hitIndex, BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt) |
| | | protected virtual void OnHitEachTarget(int _hitIndex, BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, bool suckHp) |
| | | { |
| | | // ============ 获取临时数据(掉落、死亡等) ============ |
| | | int objID = (int)target.ObjID; |
| | | tempDropList.TryGetValue(objID, out BattleDrops battleDrops); |
| | | tempDeadPackList.TryGetValue(objID, out HB422_tagMCTurnFightObjDead deadPack); |
| | | tempDeadPackList.TryGetValue(objID, out BattleDeadPack deadPack); |
| | | |
| | | // 如果目标正在释放技能,跳过死亡处理(延迟到技能结束) |
| | | if (battleField != null && battleField.IsCastingSkill(target.ObjID)) |
| | | { |
| | | deadPack = null; |
| | | } |
| | | |
| | | // ============ 参数打包 ============ |
| | | BattleHurtParam hurtParam = BattleUtility.CalcBattleHurtParam(this, _hitIndex, target, hurt, battleDrops, deadPack); |
| | | |
| | | BattleHurtParam hurtParam = BattleUtility.CalcBattleHurtParam(this, _hitIndex, target, hurt, battleDrops, deadPack, suckHp); |
| | | #if UNITY_EDITOR |
| | | PrintHurtParamDebugInfo(hurtParam); |
| | | #endif |
| | |
| | | // ============ 获取临时数据(掉落、死亡等) ============ |
| | | int objID = (int)target.ObjID; |
| | | tempDropList.TryGetValue(objID, out BattleDrops battleDrops); |
| | | tempDeadPackList.TryGetValue(objID, out HB422_tagMCTurnFightObjDead deadPack); |
| | | |
| | | tempDeadPackList.TryGetValue(objID, out BattleDeadPack deadPack); |
| | | |
| | | // 如果目标正在释放技能,跳过死亡处理(延迟到技能结束) |
| | | if (battleField != null && battleField.IsCastingSkill(target.ObjID)) |
| | | { |
| | | deadPack = null; |
| | | } |
| | | // ============ 参数打包(将 tagSCUseSkillHurtEx 转换为 tagSCUseSkillHurt)============ |
| | | HB427_tagSCUseSkill.tagSCUseSkillHurt hurt = new HB427_tagSCUseSkill.tagSCUseSkillHurt |
| | | { |
| | |
| | | HurtHPEx = hurtEx.HurtHPEx, |
| | | CurHP = hurtEx.CurHP, |
| | | CurHPEx = hurtEx.CurHPEx, |
| | | SuckHP = hurtEx.SuckHP, |
| | | SuckHP = 0,//hurtEx.SuckHP, 获取全部吸血时已经计算过 这里就不再计算 |
| | | BounceHP = 0, // HurtEx 没有反伤字段 |
| | | HurtCountEx = 0, |
| | | HurtListEx = null |
| | | }; |
| | | |
| | | BattleHurtParam hurtParam = BattleUtility.CalcBattleHurtParam(this, _hitIndex, target, hurt, battleDrops, deadPack); |
| | | |
| | | #if UNITY_EDITOR |
| | | PrintHurtParamDebugInfo(hurtParam); |
| | | #endif |
| | | |
| | | // 先调用目标受伤 |
| | | target.Hurt(hurtParam); |
| | | |
| | | // 再调用施法者吸血/反伤 |
| | | caster.OnHurtTarget(hurtParam); |
| | | OnHitEachTarget(_hitIndex, target, hurt, false);//获取全部吸血时已经计算过 这里就不再计算 |
| | | } |
| | | |
| | | #if UNITY_EDITOR |
| | |
| | | // 处理死亡相关逻辑:分配掉落和经验 |
| | | protected void HandleDead() |
| | | { |
| | | var deadPackList = BattleUtility.FindDeadPack(packList); |
| | | List<BattleDeadPack> deadPackList = BattleUtility.FindDeadPack(packList); |
| | | if (deadPackList.Count <= 0) return; |
| | | |
| | | CheckAfterDeadhPack(); |
| | |
| | | // 构造BattleDrops并缓存 |
| | | for (int i = 0; i < deadPackList.Count; i++) |
| | | { |
| | | int objID = (int)deadPackList[i].ObjID; |
| | | BattleDeadPack battleDeadPack = deadPackList[i]; |
| | | int objID = (int)battleDeadPack.deadPack.ObjID; |
| | | BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject(objID); |
| | | |
| | | // 修复:添加空值检查 |
| | |
| | | } |
| | | |
| | | // 修复:避免在遍历时修改集合,先收集后删除 |
| | | var deadPacksToRemove = new List<GameNetPackBasic>(deadPackList.Cast<GameNetPackBasic>()); |
| | | var deadPacksToRemove = new List<GameNetPackBasic>(deadPackList.Select(d => d.deadPack)); |
| | | deadPacksToRemove.AddRange(deadPackList.Where(d => d.deadTriggerSkill != null).Select(d => d.deadTriggerSkill)); |
| | | foreach (var deadPack in deadPacksToRemove) |
| | | { |
| | | packList.Remove(deadPack); |
| | |
| | | packList.RemoveAt(removeIndexList[i]); |
| | | } |
| | | |
| | | |
| | | public virtual bool IsFinishedForJudge() |
| | | { |
| | | if (!isPlay) return false; |
| | | |
| | | if (skillEffect != null) |
| | | { |
| | | if (!skillEffect.IsFinished()) return false; |
| | | } |
| | | |
| | | if (otherSkillActionList.Count > 0) |
| | | { |
| | | foreach (var action in otherSkillActionList) |
| | | { |
| | | if (!action.IsFinishedForJudge()) return false; |
| | | } |
| | | } |
| | | |
| | | if (isFinished && moveFinished) |
| | | { |
| | | if (packList.Count > 0) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | // 检查技能是否完成:综合检查所有完成条件 |
| | | public virtual bool IsFinished() |
| | | { |
| | |
| | | return false; |
| | | } |
| | | |
| | | // 技能完全结束,移除技能注册并触发延迟的死亡判定 |
| | | if (battleField != null && caster != null) |
| | | { |
| | | battleField.RemoveCastingSkill(caster.ObjID, this); |
| | | |
| | | battleField.OnObjsDead(new List<BattleDeadPack>(tempDeadPackList.Values)); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | |
| | | // 强制结束技能:立即结束所有技能相关的处理 |
| | | public virtual void ForceFinished() |
| | | { |
| | | if (isFinished) |
| | | return; |
| | | |
| | | // 移除技能注册 |
| | | if (battleField != null && caster != null) |
| | | { |
| | | battleField.RemoveCastingSkill(caster.ObjID, this); |
| | | } |
| | | |
| | | battleField.OnObjsDead(new List<BattleDeadPack>(tempDeadPackList.Values)); |
| | | |
| | | // 1. 强制结束技能效果 |
| | | skillEffect?.ForceFinished(); |
| | | skillEffect = null; |
| | | |
| | | foreach (var subSkillPack in tagUseSkillAttack.subSkillList) |
| | | { |
| | | SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, new List<GameNetPackBasic>() { subSkillPack }); |
| | | recordAction.fromSkill = this; |
| | | otherSkillActionList.Add(recordAction); |
| | | battleField.recordPlayer.ImmediatelyPlay(recordAction); |
| | | } |
| | | tagUseSkillAttack.subSkillList.Clear(); |
| | | foreach (var subCombinePack in tagUseSkillAttack.subSkillCombinePackList) |
| | | { |
| | | SkillRecordAction recordAction = CustomHB426CombinePack.CreateSkillAction(battleField.guid, subCombinePack.packList); |
| | | recordAction.fromSkill = this; |
| | | otherSkillActionList.Add(recordAction); |
| | | battleField.recordPlayer.ImmediatelyPlay(recordAction); |
| | | } |
| | | tagUseSkillAttack.subSkillCombinePackList.Clear(); |
| | | |
| | | // 2. 强制结束所有子技能动作 |
| | | otherSkillActionList.ForEach(action => action.ForceFinish()); |
| | | otherSkillActionList.Clear(); |
| | | |
| | | // 3. 清理 DOTween 动画(防止移动回调在战斗结束后执行) |
| | | if (caster != null && caster.heroRectTrans != null) |
| | | { |
| | | DG.Tweening.DOTween.Kill(caster.heroRectTrans); |
| | | } |
| | | |
| | | // 4. 重置施法者状态 |
| | | if (caster != null) |
| | | { |
| | | // 重置位置到原点 |
| | | if (caster.heroRectTrans != null) |
| | | { |
| | | caster.heroRectTrans.anchoredPosition = Vector2.zero; |
| | | } |
| | | |
| | | // 重置朝向 |
| | | if (caster.heroGo != null) |
| | | { |
| | | Vector3 scale = caster.heroGo.transform.localScale; |
| | | scale.x = Mathf.Abs(scale.x); |
| | | caster.heroGo.transform.localScale = scale; |
| | | } |
| | | |
| | | // 取消幻影效果 |
| | | caster.motionBase?.ShowIllusionShadow(false); |
| | | |
| | | // 播放待机动画(如果还活着) |
| | | if (!caster.teamHero.isDead) |
| | | { |
| | | caster.motionBase?.ResetForReborn(false); |
| | | } |
| | | } |
| | | |
| | | // 5. 恢复 UI 状态 |
| | | if (battleField != null) |
| | | { |
| | | // 恢复所有角色的显示层级和血条 |
| | | var allList = battleField.battleObjMgr?.allBattleObjDict?.Values; |
| | | if (allList != null) |
| | | { |
| | | foreach (BattleObject bo in allList) |
| | | { |
| | | bo.layerMgr?.SetFront(); |
| | | bo.heroInfoBar?.SetActive(true); |
| | | } |
| | | } |
| | | |
| | | // 关闭技能遮罩 |
| | | if (battleField.battleRootNode != null && battleField.battleRootNode.skillMaskNode != null) |
| | | { |
| | | battleField.battleRootNode.skillMaskNode.SetActive(false); |
| | | } |
| | | } |
| | | |
| | | isFinished = true; |
| | | moveFinished = true; |
| | | isPlay = true; |
| | | |
| | | // 处理所有剩余包 |
| | | // 6. 处理所有剩余包(包括 buff 包) |
| | | // 先处理 buffPackCollections |
| | | DistributeBuffPacks(buffPackCollections); |
| | | buffPackCollections.Clear(); |
| | | |
| | | // 处理剩余的 packList |
| | | while (packList.Count > 0) |
| | | { |
| | | var pack = packList[0]; |
| | |
| | | otherSkillActionList.Add(otherSkillAction); |
| | | return false; |
| | | } |
| | | else if (pack is HB428_tagSCBuffRefresh buffRefresh) |
| | | else if (IsBuffPack(pack)) |
| | | { |
| | | // 从找到第一个HB428开始 找出连续的HB428_tagSCBuffRefresh包 如果找到一个B428后 之后碰到非HB428包就停止 |
| | | buffCollections.Add(buffRefresh); |
| | | // 从找到第一个 Buff 包开始,收集连续的 HB428/HB429 包 |
| | | buffPackCollections.Add(pack); |
| | | while (packList.Count > 0) |
| | | { |
| | | var nextPack = packList[0]; |
| | | if (nextPack is HB428_tagSCBuffRefresh nextBuffRefresh) |
| | | if (IsBuffPack(nextPack)) |
| | | { |
| | | buffCollections.Add(nextBuffRefresh); |
| | | buffPackCollections.Add(nextPack); |
| | | packList.RemoveAt(0); |
| | | } |
| | | else |
| | |
| | | } |
| | | } |
| | | |
| | | // 同时刷新所有对象的buff,不分组 |
| | | foreach (var buff in buffCollections) |
| | | { |
| | | BattleObject battleObj = battleField.battleObjMgr.GetBattleObject((int)buff.ObjID); |
| | | if (battleObj != null) |
| | | { |
| | | battleObj.buffMgr.RefreshBuff(buff, true); |
| | | } |
| | | } |
| | | // 处理所有收集到的 buff 包 |
| | | ProcessBuffPacks(buffPackCollections); |
| | | |
| | | // 清空已处理的buff集合 |
| | | buffCollections.Clear(); |
| | | // 清空已处理的 buff 集合 |
| | | buffPackCollections.Clear(); |
| | | continue; |
| | | } |
| | | |
| | |
| | | otherSkillActionList?.Clear(); |
| | | dropPackList?.Clear(); |
| | | expPackList?.Clear(); |
| | | buffPackCollections?.Clear(); |
| | | |
| | | skillEffect = null; |
| | | packList = null; |
| | | } |
| | | |
| | | #region Buff包处理 |
| | | |
| | | /// <summary> |
| | | /// 判断是否为 Buff 相关的包(HB428 或 HB429) |
| | | /// </summary> |
| | | protected bool IsBuffPack(GameNetPackBasic pack) |
| | | { |
| | | return pack is HB428_tagSCBuffRefresh || pack is HB429_tagSCBuffDel; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理收集到的 Buff 包列表(HB428 刷新 和 HB429 删除) |
| | | /// </summary> |
| | | protected void ProcessBuffPacks(List<GameNetPackBasic> buffPacks) |
| | | { |
| | | if (buffPacks == null || buffPacks.Count == 0) return; |
| | | |
| | | foreach (var pack in buffPacks) |
| | | { |
| | | if (pack is HB428_tagSCBuffRefresh buffRefresh) |
| | | { |
| | | BattleObject battleObj = battleField.battleObjMgr.GetBattleObject((int)buffRefresh.ObjID); |
| | | if (battleObj != null) |
| | | { |
| | | battleObj.buffMgr.RefreshBuff(buffRefresh, true); |
| | | } |
| | | } |
| | | else if (pack is HB429_tagSCBuffDel buffDel) |
| | | { |
| | | BattleObject battleObj = battleField.battleObjMgr.GetBattleObject((int)buffDel.ObjID); |
| | | if (battleObj != null) |
| | | { |
| | | battleObj.buffMgr.RemoveBuff(buffDel, false); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 强制分发 Buff 包(用于 ForceFinished 场景) |
| | | /// </summary> |
| | | protected void DistributeBuffPacks(List<GameNetPackBasic> buffPacks) |
| | | { |
| | | if (buffPacks == null || buffPacks.Count == 0) return; |
| | | |
| | | foreach (var pack in buffPacks) |
| | | { |
| | | PackageRegedit.Distribute(pack); |
| | | } |
| | | } |
| | | |
| | | #endregion |
| | | |
| | | } |