using System.Collections.Generic; using System.Linq; using UnityEngine; // SkillBase(Death 部分):死亡包、HP 刷新、掉落、经验的收集与分配。 public partial class SkillBase { // 处理HP刷新包(简化逻辑) private void HandleRefreshHP() { // 查找HP刷新包 HB419_tagSCObjHPRefresh refreshPack = BattleUtility.FindObjHPRefreshPack(packList); if (refreshPack != null) { // 分发HP刷新包 // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:HP刷新包是技能内部产生的,应该由当前SkillRecordAction的innerRecordPlayer管理 // 这样可以确保HP刷新与技能的生命周期绑定,ForceFinish时一并处理 PackageRegeditEx.DistributeToRecordAction(refreshPack, ownRecordAction); packList.Remove(refreshPack); } } // 处理死亡相关逻辑:分配掉落和经验 protected void HandleDead() { List deadPackList = BattleUtility.FindDeadPack(packList); if (deadPackList.Count <= 0) return; foreach (var deadPack in deadPackList) { packList.Remove(deadPack.deadPack); packList.Remove(deadPack.deadTriggerSkill); } // 找到最大的死亡包 packUID BattleDeadPack lastBattleDeadPack = null; ulong maxDeathPackUID = 0; foreach (var deadPack in deadPackList) { if (deadPack.deadPack != null && deadPack.deadPack.packUID > maxDeathPackUID) { maxDeathPackUID = deadPack.deadPack.packUID; lastBattleDeadPack = deadPack; } } // 如果找到了死亡包,收集所有 packUID > maxDeathPackUID 的包 if (maxDeathPackUID > 0 && lastBattleDeadPack != null) { BattleDebug.LogError($"SkillBase.HandleDead: 找到死亡包,maxDeathPackUID = {maxDeathPackUID},开始收集死亡后的包"); // 1. 收集 packList 中 packUID 大于死亡包的包(排除经验包和掉落包,它们需要在当前技能中处理) List packsToRemove = new List(); foreach (var pack in packList) { ulong packUID = GetPackUID(pack); if (packUID > maxDeathPackUID) { // 排除经验包和掉落包,它们属于当前死亡事件的一部分,不是"死亡后"的包 if (pack is HB405_tagMCAddExp expPack && expPack.Source == 2 || (pack is H0704_tagRolePackRefresh h0704 && h0704.PackType == (byte)PackType.DropItem && h0704.IsBind == 1)) { continue; // 跳过经验包和掉落包,让 CheckAfterDeadhPack() 处理它们 } BattleDebug.LogError($"SkillBase.HandleDead: 从packList收集死亡后的包 - Type: {pack.GetType().Name}, UID: {packUID}"); lastBattleDeadPack.packListAfterDeath.Add(pack); packsToRemove.Add(pack); } } packList.RemoveAll(p => packsToRemove.Contains(p)); } CheckAfterDeadhPack(); // 修复:先收集要删除的包,避免在foreach中修改集合 var dropPacksToRemove = new List(dropPackList); foreach (var _dropPack in dropPacksToRemove) { // 【使用 parentRecordAction.innerRecordPlayer】 // 原因:掉落包是技能效果的一部分,应该由当前SkillRecordAction管理 // 掉落包的分发与技能完成绑定,确保在技能ForceFinish时正确处理 PackageRegeditEx.DistributeToRecordAction(_dropPack, ownRecordAction); packList.Remove(_dropPack); } // 获取并分配掉落物品和经验 var dropPack = PackManager.Instance.GetSinglePack(PackType.DropItem); var itemDict = dropPack.GetAllItems(); List itemList = new List(itemDict.Values.Where(item => item != null && item.isAuction)); var dropAssign = AssignDrops(itemList, deadPackList.Count); var expAssign = AssignExp(expPackList, deadPackList.Count); // 构造BattleDrops并缓存 for (int i = 0; i < deadPackList.Count; i++) { BattleDeadPack bdp = deadPackList[i]; int objID = (int)bdp.deadPack.ObjID; BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject(objID); // 修复:添加空值检查 if (deadTarget == null) { Debug.LogError($"找不到死亡目标,ObjID: {objID}"); continue; } List itemIndexList = dropAssign[i].Select(item => item.gridIndex).ToList(); BattleDrops battleDrops = new BattleDrops() { rectTransform = deadTarget.GetRectTransform(), dropItemPackIndex = itemIndexList, expDrops = expAssign[i] }; // 修复:避免字典键冲突,使用安全的添加方式 if (!tempDropList.ContainsKey(objID)) { tempDropList.Add(objID, battleDrops); } else { Debug.LogWarning($"tempDropList中已存在ObjID={objID}的记录,将覆盖原值"); tempDropList[objID] = battleDrops; // 覆盖现有值 } if (!tempDeadPackList.ContainsKey(objID)) { tempDeadPackList.Add(objID, deadPackList[i]); } else { Debug.LogWarning($"tempDeadPackList中已存在ObjID={objID}的记录,将覆盖原值"); tempDeadPackList[objID] = deadPackList[i]; // 覆盖现有值 } } // 修复:避免在遍历时修改集合,先收集后删除 var deadPacksToRemove = new List(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); } } // 分配掉落物品:将掉落物品平均分配给死亡对象 protected List> AssignDrops(List itemList, int deadCount) { var dropAssign = new List>(); for (int i = 0; i < deadCount; i++) dropAssign.Add(new List()); for (int i = 0; i < itemList.Count; i++) dropAssign[i % deadCount].Add(itemList[i]); return dropAssign; } // 获取包的 packUID protected ulong GetPackUID(GameNetPackBasic pack) { if (pack == null) return 0; if (pack is HB422_tagMCTurnFightObjDead deadPack) return deadPack.packUID; if (pack is CustomHB426CombinePack combinePack) { var mainSkillPack = combinePack.GetMainHB427SkillPack(); return mainSkillPack?.packUID ?? 0; } if (pack is HB427_tagSCUseSkill skillPack) return skillPack.packUID; if (pack is HB428_tagSCBuffRefresh buffRefresh) return buffRefresh.packUID; if (pack is HB429_tagSCBuffDel buffDel) return buffDel.packUID; if (pack is HB419_tagSCObjHPRefresh hpRefresh) return hpRefresh.packUID; if (pack is HB405_tagMCAddExp expPack) return expPack.packUID; if (pack is H0704_tagRolePackRefresh dropPack) return dropPack.packUID; // 尝试通过反射获取 packUID var packUIDField = pack.GetType().GetField("packUID"); if (packUIDField != null) { return (ulong)packUIDField.GetValue(pack); } return 0; } // 分配经验值:将经验包平均分配给每个死亡对象 protected List> AssignExp(List expList, int deadCount) { var expAssign = new List>(); for (int i = 0; i < deadCount; i++) expAssign.Add(new List()); // 修复:检查除零风险 if (deadCount == 0) { Debug.LogWarning("AssignExp: deadCount为0,无法分配经验"); return expAssign; } // 修复:先收集要删除的包,避免在foreach中修改packList var expPacksToRemove = new List(); 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); var newPack = new HB405_tagMCAddExp { Exp = (uint)(assignExp % Constants.ExpPointValue), ExpPoint = (uint)(assignExp / Constants.ExpPointValue), Source = expPack.Source }; expAssign[i].Add(newPack); } expPacksToRemove.Add(expPack); } // 统一删除收集的包 foreach (var pack in expPacksToRemove) { packList.Remove(pack); } return expAssign; } /// /// 将 tempDeadPackList 里 pending 的死亡包投递给 BattleField 生成 DeathRecordAction。 /// 合并 IsFinished(正常结束)与 ForceFinished(强制结束)两条路径的共同部分。 /// /// /// true:把 DeathRecordAction 绑定到 ownRecordAction(正常结束,死亡动作会等待当前技能完成); /// false:不绑定(强制结束,死亡动作立即在默认 RecordPlayer 里播放)。 /// /// /// true:无论是否投递成功都清空 tempDeadPackList(ForceFinished 语义); /// false:仅在成功投递 DeathRecordAction 时清空(IsFinished 语义)。 /// /// 是否成功投递了 DeathRecordAction。 protected bool FlushPendingDeathActions(bool useInnerPlayer, bool clearEvenIfNotDispatched) { // 防御:battleField / caster 任一为 null 时直接返回,避免 NullReferenceException。 if (battleField == null || caster == null) { if (clearEvenIfNotDispatched) tempDeadPackList.Clear(); return false; } // 统一做的事:从战场 casting 注册里移除自身。 battleField.RemoveCastingSkill(caster.ObjID, this); var deadPacks = new List(tempDeadPackList.Values); // 两条路径的唯一差别:是否把 DeathRecordAction 绑定到 ownRecordAction(让死亡动作等技能完成)。 DeathRecordAction recordAction = useInnerPlayer ? battleField.OnObjsDead(deadPacks, null, ownRecordAction) : battleField.OnObjsDead(deadPacks); if (null != recordAction && ownRecordAction != null) { ownRecordAction.GetInnerRecordPlayer().ImmediatelyPlay(recordAction); tempDeadPackList.Clear(); return true; } if (clearEvenIfNotDispatched) { tempDeadPackList.Clear(); } return false; } // 检查死亡后的包处理:处理技能包、掉落包、经验包 protected void CheckAfterDeadhPack() { List removeIndexList = new List(); for (int i = 0; i < packList.Count; i++) { var pack = packList[i]; // 复活基本都靠技能包 if (pack is CustomHB426CombinePack combinePack && combinePack.startTag.Tag.StartsWith("Skill_")) break; if (pack is H0704_tagRolePackRefresh h0704Pack && h0704Pack.PackType == (byte)PackType.DropItem && h0704Pack.IsBind == 1) { dropPackList.Add(h0704Pack); removeIndexList.Add(i); } if (pack is HB405_tagMCAddExp h405Pack && h405Pack.Source == 2) { expPackList.Add(h405Pack); removeIndexList.Add(i); } } for (int i = removeIndexList.Count - 1; i >= 0; i--) packList.RemoveAt(removeIndexList[i]); } }