yyl
2025-08-07 d767a5a0efbac267507be14b5b09bd64015fe560
125 【战斗】战斗系统 技能表 部分战斗内容
29个文件已修改
14个文件已添加
1562 ■■■■ 已修改文件
Main/Config/Configs/DamageNumConfig.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/DamageNumConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/PlayerAttrConfig.cs 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/PlayerAttrConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/SkillConfig.cs 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ClientPack/CB4_FightDefine/CB415_tagCSMainDropItemOP.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ClientPack/CB4_FightDefine/CB415_tagCSMainDropItemOP.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0407_tagNPCDisappear.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/H06_PlayerVsNPC/DTC0604_tagUseSkillAttack.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB405_tagMCAddExp.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB405_tagMCAddExp.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB424_tagSCTurnFightInit.cs 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB425_tagSCTurnFightReportSign.cs 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB405_tagMCAddExp.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB405_tagMCAddExp.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleConst.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleEffectMgr.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleRootNode.cs 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/OperationAgent/HandModeOperationAgent.cs 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/StoryBattleField.cs 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleHUDWin.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleManager.cs 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObjMgr.cs 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleTweenMgr.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleUtility.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleWin.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Define/DamageType.cs 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordPlayer.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyDamageSkill.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyHealSkill.cs 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyHealSkill.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/RebornSkill.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/RebornSkill.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillBase.cs 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletSkillEffect.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/KnapSack/Logic/ItemLogicUtility.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Team/TeamManager.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/EnumHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/DamageNumConfig.cs
New file
@@ -0,0 +1,62 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2025年8月6日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class DamageNumConfig : ConfigBase<string, DamageNumConfig>
{
    static DamageNumConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public string id;
    public int prefix;
    public int plus;
    public int minus;
    public int[] nums;
    public override string LoadKey(string _key)
    {
        string key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        id = tables[0];
            int.TryParse(tables[1],out prefix);
            int.TryParse(tables[2],out plus);
            int.TryParse(tables[3],out minus);
            if (tables[4].Contains("["))
            {
                nums = JsonMapper.ToObject<int[]>(tables[4]);
            }
            else
            {
                string[] numsStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                nums = new int[numsStringArray.Length];
                for (int i=0;i<numsStringArray.Length;i++)
                {
                     int.TryParse(numsStringArray[i],out nums[i]);
                }
            }
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/DamageNumConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8189c5d3b27328346a2b8b3eb50d45cf
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/PlayerAttrConfig.cs
New file
@@ -0,0 +1,65 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2025年8月5日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class PlayerAttrConfig : ConfigBase<int, PlayerAttrConfig>
{
    static PlayerAttrConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int ID;
    public string Name;
    public string ShowName;
    public int ISPercentage;
    public int type;
    public int decimalCount;
    public int showType;
    public int showSequence;
    public string desc;
    public string Parameter;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out ID);
            Name = tables[1];
            ShowName = tables[2];
            int.TryParse(tables[3],out ISPercentage);
            int.TryParse(tables[4],out type);
            int.TryParse(tables[5],out decimalCount);
            int.TryParse(tables[6],out showType);
            int.TryParse(tables[7],out showSequence);
            desc = tables[8];
            Parameter = tables[9];
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/PlayerAttrConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1fc6e60e5eeba644bf77f0c7b22879e
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/SkillConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2025年8月5日
//    [  Date ]:           2025年8月7日
//--------------------------------------------------------
using System.Collections.Generic;
@@ -17,16 +17,22 @@
    }
    public int SkillID;
    public int SkillTypeID;
    public int SkillMaxLV;
    public string SkillName;
    public string Description;
    public string IconName;
    public int FuncType;
    public int SkillType;
    public int HurtType;
    public int AtkType;
    public int TagAim;
    public int TagFriendly;
    public int TagAffect;
    public int TagCount;
    public int HappenRate;
    public int LastTime;
    public int CoolDownTime;
    public int Priority;
    public int EffectID1;
    public int[] EffectValues1;
    public int EffectID2;
@@ -54,6 +60,7 @@
    public int EffectId;
    public int EffectPos;
    public int EffectType;
    public string IconName;
    public override int LoadKey(string _key)
    {
@@ -67,35 +74,47 @@
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out SkillID); 
            SkillName = tables[1];
            int.TryParse(tables[1],out SkillTypeID);
            Description = tables[2];
            int.TryParse(tables[2],out SkillMaxLV);
            IconName = tables[3];
            SkillName = tables[3];
            int.TryParse(tables[4],out FuncType);
            Description = tables[4];
            int.TryParse(tables[5],out SkillType);
            int.TryParse(tables[5],out FuncType);
            int.TryParse(tables[6],out HurtType);
            int.TryParse(tables[6],out SkillType);
            int.TryParse(tables[7],out AtkType);
            int.TryParse(tables[7],out HurtType);
            int.TryParse(tables[8],out TagAim);
            int.TryParse(tables[8],out AtkType);
            int.TryParse(tables[9],out LastTime);
            int.TryParse(tables[9],out TagAim);
            int.TryParse(tables[10],out CoolDownTime);
            int.TryParse(tables[10],out TagFriendly);
            int.TryParse(tables[11],out EffectID1);
            int.TryParse(tables[11],out TagAffect);
            if (tables[12].Contains("["))
            int.TryParse(tables[12],out TagCount);
            int.TryParse(tables[13],out HappenRate);
            int.TryParse(tables[14],out LastTime);
            int.TryParse(tables[15],out CoolDownTime);
            int.TryParse(tables[16],out Priority);
            int.TryParse(tables[17],out EffectID1);
            if (tables[18].Contains("["))
            {
                EffectValues1 = JsonMapper.ToObject<int[]>(tables[12]);
                EffectValues1 = JsonMapper.ToObject<int[]>(tables[18]);
            }
            else
            {
                string[] EffectValues1StringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] EffectValues1StringArray = tables[18].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues1 = new int[EffectValues1StringArray.Length];
                for (int i=0;i<EffectValues1StringArray.Length;i++)
                {
@@ -103,15 +122,15 @@
                }
            }
            int.TryParse(tables[13],out EffectID2);
            int.TryParse(tables[19],out EffectID2);
            if (tables[14].Contains("["))
            if (tables[20].Contains("["))
            {
                EffectValues2 = JsonMapper.ToObject<int[]>(tables[14]);
                EffectValues2 = JsonMapper.ToObject<int[]>(tables[20]);
            }
            else
            {
                string[] EffectValues2StringArray = tables[14].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] EffectValues2StringArray = tables[20].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues2 = new int[EffectValues2StringArray.Length];
                for (int i=0;i<EffectValues2StringArray.Length;i++)
                {
@@ -119,15 +138,15 @@
                }
            }
            int.TryParse(tables[15],out EffectID3);
            int.TryParse(tables[21],out EffectID3);
            if (tables[16].Contains("["))
            if (tables[22].Contains("["))
            {
                EffectValues3 = JsonMapper.ToObject<int[]>(tables[16]);
                EffectValues3 = JsonMapper.ToObject<int[]>(tables[22]);
            }
            else
            {
                string[] EffectValues3StringArray = tables[16].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] EffectValues3StringArray = tables[22].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues3 = new int[EffectValues3StringArray.Length];
                for (int i=0;i<EffectValues3StringArray.Length;i++)
                {
@@ -135,15 +154,15 @@
                }
            }
            int.TryParse(tables[17],out ConnSkill);
            int.TryParse(tables[23],out ConnSkill);
            if (tables[18].Contains("["))
            if (tables[24].Contains("["))
            {
                EnhanceSkillList = JsonMapper.ToObject<int[]>(tables[18]);
                EnhanceSkillList = JsonMapper.ToObject<int[]>(tables[24]);
            }
            else
            {
                string[] EnhanceSkillListStringArray = tables[18].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] EnhanceSkillListStringArray = tables[24].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EnhanceSkillList = new int[EnhanceSkillListStringArray.Length];
                for (int i=0;i<EnhanceSkillListStringArray.Length;i++)
                {
@@ -151,43 +170,45 @@
                }
            }
            int.TryParse(tables[19],out FightPower);
            int.TryParse(tables[25],out FightPower);
            int.TryParse(tables[20],out StartupFrames);
            int.TryParse(tables[26],out StartupFrames);
            int.TryParse(tables[21],out ActiveFrames);
            int.TryParse(tables[27],out ActiveFrames);
            int.TryParse(tables[22],out RecoveryFrames);
            int.TryParse(tables[28],out RecoveryFrames);
            int.TryParse(tables[23],out LoopCount);
            int.TryParse(tables[29],out LoopCount);
            int.TryParse(tables[24],out CastPosition);
            int.TryParse(tables[30],out CastPosition);
            int.TryParse(tables[25],out CastIndexNum);
            int.TryParse(tables[31],out CastIndexNum);
            float.TryParse(tables[26],out CastDistance);
            float.TryParse(tables[32],out CastDistance);
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[27].Replace("(", "[").Replace(")", "]"));
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[33].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[28],out BulletEffectId);
            int.TryParse(tables[34],out BulletEffectId);
            int.TryParse(tables[29],out BulletPos);
            int.TryParse(tables[35],out BulletPos);
            int.TryParse(tables[30],out BulletPath);
            int.TryParse(tables[36],out BulletPath);
            int.TryParse(tables[31],out BulletFlyTime);
            int.TryParse(tables[37],out BulletFlyTime);
            int.TryParse(tables[32],out ExplosionEffectId);
            int.TryParse(tables[38],out ExplosionEffectId);
            int.TryParse(tables[33],out ExplosionPos);
            int.TryParse(tables[39],out ExplosionPos);
            SkillMotionName = tables[34];
            SkillMotionName = tables[40];
            int.TryParse(tables[35],out EffectId);
            int.TryParse(tables[41],out EffectId);
            int.TryParse(tables[36],out EffectPos);
            int.TryParse(tables[42],out EffectPos);
            int.TryParse(tables[37],out EffectType);
            int.TryParse(tables[43],out EffectType);
            IconName = tables[44];
        }
        catch (Exception exception)
        {
Main/Core/NetworkPackage/ClientPack/CB4_FightDefine/CB415_tagCSMainDropItemOP.cs
New file
@@ -0,0 +1,24 @@
using UnityEngine;
using System.Collections;
// B4 15 主线掉落物品操作 #tagCSMainDropItemOP
public class CB415_tagCSMainDropItemOP : GameNetPackBasic {
    public byte Count;
    public  ushort[] IndexList;    // 掉落背包中的物品格子索引列表
    public byte OPType;    // 0 - 拾取非装备物品;1 - 分解;2 - 穿戴/替换;
    public byte OPValue;    // 操作额外指令值,由操作类型决定,如穿戴时可发送穿戴后是否自动分解
    public CB415_tagCSMainDropItemOP () {
        combineCmd = (ushort)0x03FE;
        _cmd = (ushort)0xB415;
    }
    public override void WriteToBytes () {
        WriteBytes (Count, NetDataType.BYTE);
        WriteBytes (IndexList, NetDataType.WORD, Count);
        WriteBytes (OPType, NetDataType.BYTE);
        WriteBytes (OPValue, NetDataType.BYTE);
    }
}
Main/Core/NetworkPackage/ClientPack/CB4_FightDefine/CB415_tagCSMainDropItemOP.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 869e528814e57b34cb674f8b554a911f
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -5,9 +5,9 @@
public class CustomHB426CombinePack : GameNetPackBasic
{
    protected HB426_tagSCTurnFightTag startTag;
    public HB426_tagSCTurnFightTag startTag;
    protected HB426_tagSCTurnFightTag endTag;
    public HB426_tagSCTurnFightTag endTag;
    public int fromIndex;
@@ -139,10 +139,12 @@
            return;
        }
        //  技能包
        if (startTag.Tag.StartsWith("Skill_"))
        {
            H0604_tagUseSkillAttack skill = packList[0] as H0604_tagUseSkillAttack;
            BattleObject caster = battleField.battleObjMgr.GetBattleObject((int)skill.ObjID);
            //  注意处理packList
            SkillRecordAction skillRecordAction = new SkillRecordAction(battleField, caster, skill, packList);
            battleField.PlayRecord(skillRecordAction);
        }
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0407_tagNPCDisappear.cs
@@ -11,9 +11,9 @@
        //玩家主动点击休息时,后端会回收创建的战斗主阵容武将实例,前端收到//04 07 NPC消失#tagNPCDisappear时进行解绑
        BattleField battleField = BattleManager.Instance.GetBattleField(vNetPack.packUID);
        //04 07 NPC消失#tagNPCDisappear 中的字段NPCID实际上同步的是ObjID,只是命名问题
        //    提前结束战斗 删除NPCID()实际上是对象的ObjID
        battleField.FinishBattleInAdvance(vNetData.NPCID);
        battleField.NPCDisappear(vNetData.NPCID);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/H06_PlayerVsNPC/DTC0604_tagUseSkillAttack.cs
@@ -6,7 +6,7 @@
public class DTC0604_tagUseSkillAttack : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        H0604_tagUseSkillAttack vNetData = vNetPack as H0604_tagUseSkillAttack;
        // H0604_tagUseSkillAttack vNetData = vNetPack as H0604_tagUseSkillAttack;
    // public uint ObjID;
@@ -20,9 +20,9 @@
        // ObjType类型的ObjID使用BattleType类技能SkillID攻击了AttackObjType类型的AttackID 伤害数字是HurtList
        BattleField battleField = BattleManager.Instance.GetBattleField(vNetPack.packUID);
        // BattleField battleField = BattleManager.Instance.GetBattleField(vNetPack.packUID);
        battleField.ProcessUseSkillAttack(vNetData);
        // battleField.ProcessUseSkillAttack(vNetData);
    }
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB405_tagMCAddExp.cs
New file
@@ -0,0 +1,11 @@
using UnityEngine;
using System.Collections;
//B4 05 获得经验 #tagMCAddExp
public class DTCB405_tagMCAddExp : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        HB405_tagMCAddExp vNetData = vNetPack as HB405_tagMCAddExp;
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB405_tagMCAddExp.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 70b2b77edce0c7346a9df59f1266cb83
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB424_tagSCTurnFightInit.cs
@@ -57,20 +57,11 @@
            }
        }
        //    主线
        // if (vNetData.MapID <= 2)
        // {
        //     int chapter = (int)vNetData.FuncLineID / 10000;
        //     int wave = (int)(vNetData.MapID == 1 ? vNetData.FuncLineID % 100 : 1);//第几波怪
        //     int level = (int)(vNetData.FuncLineID % 10000) / 100;
            JsonData extendData = JsonMapper.ToObject(vNetData.Msg);
        //     BattleManager.Instance.CreateStoryBattle(chapter, wave, level, extendData, redTeamList[0], blueTeamList[0]);
        // }
        JsonData extendData = JsonMapper.ToObject(vNetData.Msg);
        string guid = BattleManager.Instance.GetGUID(vNetPack.packUID);
        BattleManager.Instance.CreateBattleField(guid, (int)vNetData.MapID, (int)vNetData.FuncLineID, extendData, redTeamList, blueTeamList);
        BattleField battleField = BattleManager.Instance.CreateBattleField(guid, (int)vNetData.MapID, (int)vNetData.FuncLineID, extendData, redTeamList, blueTeamList);
        BattleStartAction battleStartAction = new BattleStartAction(battleField);
        battleField.recordPlayer.PlayRecord(battleStartAction);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB425_tagSCTurnFightReportSign.cs
@@ -2,9 +2,30 @@
using System.Collections;
// B4 25 回合战斗战报片段标记 #tagSCTurnFightReportSign
// 战斗相关封包说明
// // B4 25 回合战斗战报片段标记 #tagSCTurnFightReportSign   后端同步战斗片段时会用该封包标记开始跟结束,中间的所有封包即为本次战斗片段的所有封包(主线小怪战斗可能包含其他非战斗类的封包,如战锤数量同步、经验同步、升级同步等)
// // B4 24 回合战斗初始化 #tagSCTurnFightInit  标记一场战斗的初始化,主线关卡分波、每波可支持多个小队,一个小队的战斗就是一场战斗
//               主线战斗中,Msg初始化信息包含  {"teamNum":当前小队编号, "teamMax":最大小队数}  , 前端如果有需要展示小队相关信息的话可以解析该值
// // B4 20 回合制战斗状态 #tagMCTurnFightState  一般同步该场战斗相关的信息,如回合变化、战斗状态等,目前State只同步 2-战斗中及 4-结算,其他有需要的话再扩展
// // B4 21 回合战斗对象开始行动 #tagMCTurnFightObjAction
//               标记某个战斗实例开始行动,后续的封包都是该次行动产生的一些列行为,直到下一个B421封包(另一个战斗实例行动)
// // B4 22 回合战斗对象死亡 #tagMCTurnFightObjDead
//               通知某个战斗实例死亡了(后端战斗实例还在),注意和0407区分,0407代表的是NPC消失了(后端战斗实例也已经销毁回收)
// // B4 23 回合战斗对象复活 #tagMCTurnFightObjReborn
// //04 07 NPC消失#tagNPCDisappear
//              注意与B422区分,0407仅代表该战斗实例被后端回收了
//             后端战斗实例会重复利用,比如切换小队时,原小队的实例会先被回收,然后再创建新的小队战斗实例,可能复用相同的实例ID,即ObjID
// //04 18 周围对象刷新#tagObjInfoRefresh
//             通知某个对象(战斗实例或者玩家自身)相关的属性刷新,如通知战斗NPC怒气值刷新,通知玩家战锤数量刷新等
// 技能通知,详见 【技能】 说明
//06 04 技能攻击使用成功#tagUseSkillAttack
//04 23 对象状态刷新通知(只显示)#tagObjPropertyRefreshView
public class DTCB425_tagSCTurnFightReportSign : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
public class DTCB425_tagSCTurnFightReportSign : DtcBasic
{
    public override void Done(GameNetPackBasic vNetPack)
    {
        base.Done(vNetPack);
        HB425_tagSCTurnFightReportSign vNetData = vNetPack as HB425_tagSCTurnFightReportSign;
@@ -16,6 +37,6 @@
    public static bool IsCorrectType(GameNetPackBasic vNetPack)
    {
        return vNetPack is HB425_tagSCTurnFightReportSign;
        return vNetPack is HB425_tagSCTurnFightReportSign;
    }
}
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB405_tagMCAddExp.cs
New file
@@ -0,0 +1,21 @@
using UnityEngine;
using System.Collections;
//B4 05 获得经验 #tagMCAddExp
public class HB405_tagMCAddExp : GameNetPackBasic {
    public uint ExpPoint;    // 单位亿点
    public uint Exp;    // 单位点
    public byte Source;    //经验获取来源
    public HB405_tagMCAddExp () {
        _cmd = (ushort)0xB405;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out ExpPoint, vBytes, NetDataType.DWORD);
        TransBytes (out Exp, vBytes, NetDataType.DWORD);
        TransBytes (out Source, vBytes, NetDataType.BYTE);
    }
}
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB405_tagMCAddExp.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 657dd96a4b0eca64386a70ac86ec48a9
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleConst.cs
@@ -5,4 +5,6 @@
    public const int BattleStartEffectID = 1001; // Example effect ID for battle start
    public const int skillMotionFps = 30;
    public const int BattlePointItemID = 3;//战锤ID
}
Main/System/Battle/BattleEffectMgr.cs
@@ -84,4 +84,19 @@
            }
        }
    }
    public void HaveRest()
    {
        foreach (KeyValuePair<int, List<EffectPlayer>> kvPair in effectDict)
        {
            foreach (EffectPlayer effectPlayer in kvPair.Value)
            {
                if (effectPlayer != null)
                {
                    GameObject.DestroyImmediate(effectPlayer.gameObject);
                }
            }
        }
        effectDict.Clear();
    }
}
Main/System/Battle/BattleField/BattleField.cs
@@ -26,24 +26,10 @@
    public JsonData extendData;
    public bool IsActive
    {
        get;
        protected set;
    }
    public bool IsBattleFinish
    {
        get;
        protected set;
    }
    public virtual bool IsPvp
    {
        get
        {
            return false;
        }
    }
    private bool m_IsPause = false;
@@ -88,6 +74,20 @@
    public BattleField(string _guid)
    {
        guid = _guid;
        GameObject go = ResManager.Instance.LoadAsset<GameObject>("Battle/Prefabs", "BattleRootNode");
        GameObject battleRootNodeGO = GameObject.Instantiate(go);
        battleRootNode = battleRootNodeGO.GetComponent<BattleRootNode>();
        battleRootNodeGO.name = this.GetType().Name;
        battleObjMgr = new BattleObjMgr();
        battleEffectMgr = new BattleEffectMgr();
        battleTweenMgr = new BattleTweenMgr();
        recordPlayer = new RecordPlayer();
        battleEffectMgr.Init(this);
        battleTweenMgr.Init(this);
        recordPlayer.Init(this);
    }
    public virtual void Init(int _MapID, int _FuncLineID, JsonData _extendData,
@@ -102,32 +102,15 @@
        redTeamIndex = 0;
        blueTeamIndex = 0;
        GameObject go = ResManager.Instance.LoadAsset<GameObject>("Battle/Prefabs", "BattleRootNode");
        GameObject battleRootNodeGO = GameObject.Instantiate(go);
        battleRootNode = battleRootNodeGO.GetComponent<BattleRootNode>();
        battleRootNodeGO.name = this.GetType().Name;
        battleObjMgr = new BattleObjMgr();
        if (blueTeamList == null)
        {
            battleObjMgr.Init(this, redTeamList[redTeamIndex], null);
            battleObjMgr.HaveRest(BattleCamp.Red);
            HaveRest();
        }
        else
        {
            battleObjMgr.Init(this, redTeamList[redTeamIndex], blueTeamList[blueTeamIndex]);
        }
        battleEffectMgr = new BattleEffectMgr();
        battleEffectMgr.Init(this);
        battleTweenMgr = new BattleTweenMgr();
        battleTweenMgr.Init(this);
        //  这里的Init交给各个子类的Init里去实现
        // battleObjMgr.Init(this, _redTeam, _blueTeam);
        recordPlayer = new RecordPlayer();
        recordPlayer.Init(this);
    }
    //  在Run之前要设置完毕 要创建Agent
@@ -227,7 +210,7 @@
    }
    public virtual void OnTurnFightState(int turnNum, int State, int FuncLineID, JsonData extendData)
    public virtual void OnTurnFightState(int turnNum, int State, int FuncLineID, JsonData turnFightStateData)
    {
        //  切换回合
        //  是每个战斗开始/每个回合的第一个战斗包
@@ -239,6 +222,13 @@
        //  TurnNum;    // 当前轮次
        //  Len;
        //  Msg;    //size = Len   +
        if (State == 4)
        {
            //已经结束并结算
            OnBattleEnd(turnFightStateData);
            return;
        }
        //  做表现
        if (turnNum == 1)
@@ -287,29 +277,12 @@
        //  销毁全部内容
    }
    public void FinishBattleInAdvance(uint[] ObjIDArr)
    public void NPCDisappear(uint[] ObjIDArr)
    {
        //  让npc隐藏后 左边播放睡觉动作
        //  让npc消失
        battleObjMgr.DestroyObjIds(ObjIDArr);
    }
    public virtual void ProcessUseSkillAttack(H0604_tagUseSkillAttack vNetData)
    {
        // H0604_tagUseSkillAttack
        // public uint ObjID;
        // public byte ObjType;
        // public byte BattleType;    //物理/魔法
        // public ushort SkillID;
        // public uint AttackID;    //主攻击目标
        // public byte AttackObjType;    //主攻击目标
        // public ushort HurtCount;    //伤害数目
        // public  tagSkillHurtObj[] HurtList;    //size = HurtCount
        // ObjType类型的ObjID使用BattleType类技能SkillID攻击了AttackObjType类型的AttackID 伤害数字是HurtList
        // SkillAction skillAction = new SkillAction();
    }
    public RectTransform GetTeamNode(BattleCamp battleCamp)
    {
@@ -323,8 +296,26 @@
        }
    }
    public RectTransform GetTeamNode(BattleCamp battleCamp, int index)
    public RectTransform GetTeamNode(BattleCamp battleCamp, BattleObject target)
    {
        int index = target.teamHero.positionNum;
        return GetTeamNode(battleCamp, index);
    }
    public RectTransform GetTeamNode(BattleCamp battleCamp, SkillConfig skillConfig)
    {
        int index = skillConfig.CastIndexNum - 1; // 技能配置的index是从1开始的,所以要减1
        return GetTeamNode(battleCamp, index);
    }
    private RectTransform GetTeamNode(BattleCamp battleCamp, int index)
    {
        if (index < 0 || index >= battleRootNode.redTeamNodeList.Count)
        {
            Debug.LogError($"GetTeamNode: Index {index} is out of range for {battleCamp} camp.");
            return null;
        }
        if (battleCamp == BattleCamp.Red)
        {
            return battleRootNode.redTeamNodeList[index].transform as RectTransform;
@@ -363,7 +354,7 @@
        foreach (var obj in redTeam)
        {
            obj.motionBase.PlayAnimation(MotionName.run, true);
            RectTransform trans = obj.heroGo.transform as RectTransform;
            RectTransform trans = obj.heroRectTrans;
            tween = trans.DOMove(obj.GetAliasTeamNode().position, 0.5f).SetEase(Ease.Linear);
            battleTweenMgr.OnPlayTween(tween);
        }
@@ -380,4 +371,58 @@
            efplayer.onDestroy += a => onMoveComplete();
        };
    }
    public void OnObjDropItem(int positionNum, ItemModel item)
    {
        // 处理掉落物品
        //无论如何图层应该在人物上面 所以这里应该有个挂点
        // YYL TODO
    }
    public void OnObjReborn(HB423_tagMCTurnFightObjReborn vNetData)
    {
        // 处理复活逻辑
        BattleObject battleObj = battleObjMgr.GetBattleObject((int)vNetData.ObjID);
        if (battleObj != null)
        {
            battleObj.OnReborn(vNetData);
        }
        else
        {
            Debug.LogError($"BattleObject with ID {vNetData.ObjID} not found for reborn.");
        }
    }
    public void OnObjDropExp(BattleObject battleObject)
    {
        // 处理掉落经验
        // YYL TODO
        battleObject.DropExp();
    }
    public virtual void OnBattleEnd(JsonData turnFightStateData)
    {
        // 处理战斗结束逻辑
        IsBattleFinish = true;
        // 结算逻辑
        // {"winFaction":获胜阵营, "statInfo":统计信息, “itemInfo“:[奖励物品信息列表]}
    }
    public virtual void HaveRest()
    {
        //  休息状态
        battleObjMgr.HaveRest(BattleCamp.Red);
        battleObjMgr.DestroyTeam(BattleCamp.Blue);
        battleEffectMgr.HaveRest();
        battleTweenMgr.HaveRest();
    }
    public bool IsBattleEnd()
    {
        return IsBattleFinish;
    }
}
Main/System/Battle/BattleField/BattleRootNode.cs
@@ -5,25 +5,48 @@
public class BattleRootNode : MonoBehaviour
{
    public RectTransform redTeamNode;
    public List<GameObject> redTeamNodeList = new List<GameObject>();
    public List<GameObject> redTeamNodeList
    {
        get
        {
            return _redTeamNodeList;
        }
    }
    private List<GameObject> _redTeamNodeList = new List<GameObject>();
    public RectTransform blueTeamNode;
    public List<GameObject> blueTeamNodeList = new List<GameObject>();
    public List<GameObject> blueTeamNodeList
    {
        get
        {
            return _blueTeamNodeList;
        }
    }
    private List<GameObject> _blueTeamNodeList = new List<GameObject>();
    public RawImage imgBackground;
    void Awake()
    {
        if (redTeamNodeList.Count != TeamConst.MaxTeamSlotCount)
        for (int i = 1; i <= TeamConst.MaxTeamSlotCount; i++)
        {
            Debug.LogError("redTeamNodeList count is not equal to MaxTeamSlotCount: " + redTeamNodeList.Count);
        }
            Transform redTrans = redTeamNode.Find("Pos" + i);
            _redTeamNodeList.Add(redTrans.gameObject);
        if (blueTeamNodeList.Count != TeamConst.MaxTeamSlotCount)
        {
            Debug.LogError("blueTeamNodeList count is not equal to MaxTeamSlotCount: " + blueTeamNodeList.Count);
            Transform blueTrans = blueTeamNode.Find("Pos" + i);
            _blueTeamNodeList.Add(blueTrans.gameObject);
        }
        DontDestroyOnLoad(gameObject);
    }
    public void SetBackground(Texture texture)
    {
        if (imgBackground != null)
        {
            imgBackground.texture = texture;
            imgBackground.SetNativeSize();
        }
    }
}
Main/System/Battle/BattleField/OperationAgent/HandModeOperationAgent.cs
@@ -1,11 +1,14 @@
using UnityEngine;
//    只有主线战斗用到 所以这里可能会放一些主线的特殊处理
public class HandModeOperationAgent : IOperationAgent
{
    protected StoryBattleField storyBattleField;
    public HandModeOperationAgent(BattleField battleField) : base(battleField)
    {
        storyBattleField = battleField as StoryBattleField;
    }
    public override void Run()
@@ -18,13 +21,63 @@
    {
        base.DoNext();
        //    当前没有在播放战斗录像
        if (!battleField.recordPlayer.IsPlaying())
        {
            //    ask for next action
            // 没有下一个包可以发了
            if (!BattleManager.Instance.DistributeNextPackage())
            {
                //    请求下一个战斗包 或者检查战斗是否结束
                // ReqType; // 0-停止战斗回城;1-设置消耗倍值;2-挑战关卡小怪;3-挑战关卡boss;4-继续战斗;
                //    如果在休息 点一下之后应该是挑战小怪或者挑战关卡
                //  如果在战斗 战斗是否结束/战斗持续中 结束应该是挑战下一关 持续应该是继续战斗
                //    检查一下锤子的消耗
                //FightPoint             用于记录消耗战锤倍数,小于等于1时默认1倍,大于1时为对应消耗倍值,0418刷新类型22
                ulong costRate = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.FightPoint);
                int cost = (int)(costRate > 1 ? costRate : 1) * 1; // 1是默认消耗
                //    检查一下锤子的消耗
                if (!ItemLogicUtility.CheckItemCount(PackType.Item, BattleConst.BattlePointItemID, cost, true))
                {
                    return;
                }
                byte reqType;
                if (storyBattleField.battleState == StoryBattleState.Break)
                {
                    reqType = 2;
                }
                else if (storyBattleField.battleState == StoryBattleState.Battle)
                {
                    if (battleField.IsBattleEnd())
                    {
                        reqType = 2; // 继续挑战小怪
                    }
                    else
                    {
                        reqType = 4; // 继续战斗
                    }
                }
                else
                {
                    Debug.LogError("unknown battle state");
                    return;
                }
                BattleManager.Instance.MainFightRequest(reqType);
            }
        }
        else
        {
            Debug.LogError("action doesnt finish, wait a moment please");
        }
    }
}
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs
@@ -5,8 +5,8 @@
{
    private bool isRun = false;
    public BattleStartAction(BattleField _battleField, BattleObject _caster, H0604_tagUseSkillAttack vNetData)
        : base(RecordActionType.BattleStart, _battleField, _caster)
    public BattleStartAction(BattleField _battleField)
        : base(RecordActionType.BattleStart, _battleField, null)
    {
        
    }
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -30,6 +30,8 @@
    private void OnDeathAnimationEnd()
    {
        // 掉落物品 增加经验
        isFinish = true;
    }
}
Main/System/Battle/BattleField/StoryBattleField.cs
@@ -3,6 +3,20 @@
using UnityEngine;
using System.Collections.Generic;
// 【主线战斗流程】
// 发送 B413  (ReqType 为 2 或 3)
//        后端回复  B425标记0开始   (中间N个战斗片段封包)  B425标记1结束
// 前端解析 N个战斗片段封包  ,拆解成前端支持的action指令,然后进行战斗表现
// 表现完毕后继续发送 B413  (ReqType 为 4)
//        后端回复  B425标记0开始   (中间N个战斗片段封包)  B425标记1结束
// 前端解析表现,然后一直循环即可
public enum StoryBattleState
{
    Break,
    Battle,
}
public class StoryBattleField : BattleField
{
    protected int chapter;//   章节
@@ -14,15 +28,26 @@
    protected MainLevelConfig levelConfig;
    public StoryBattleState battleState;
    public StoryBattleField() : base(string.Empty)
    {
    }
    public override void Init(int MapID, int FuncLineID, JsonData _extendData,
    public override void Init(int MapID, int FuncLineID, JsonData _extendData,
        List<TeamBase> _redTeamList, List<TeamBase> _blueTeamList)
    {
        base.Init(MapID, FuncLineID, extendData, _redTeamList, _blueTeamList);
        if (null == _blueTeamList || _blueTeamList.Count == 0)
        {
            battleState = StoryBattleState.Break;
        }
        else
        {
            battleState = StoryBattleState.Battle;
        }
        LoadBattleMode();
@@ -34,6 +59,13 @@
        chapterConfig = MainChapterConfig.Get(chapter);
        levelConfig = MainLevelConfig.Get(level);
        TeamManager.Instance.OnTeamChange += OnTeamChange;
    }
    public override void Release()
    {
        base.Release();
        TeamManager.Instance.OnTeamChange -= OnTeamChange;
    }
    protected void LoadBattleMode()
@@ -46,7 +78,7 @@
        SetBattleMode((BattleMode)Enum.Parse(typeof(BattleMode), savedStr));
    }
    public override void TurnFightState(int TurnNum, int State,
    public override void TurnFightState(int TurnNum, int State,
        uint FuncLineID, JsonData extendData)
    {
        base.TurnFightState(TurnNum, State, FuncLineID, extendData);
@@ -80,7 +112,34 @@
    public override void OnTurnFightState(int turnNum, int State, int FuncLineID, JsonData extendData)
    {
        base.OnTurnFightState(turnNum, State, FuncLineID, extendData);
    }
    protected void OnTeamChange(TeamType teamType)
    {
        if (teamType == TeamType.Story)
        {
            if (battleState == StoryBattleState.Break)
            {
                ReloadTeam();
            }
        }
    }
    public override void HaveRest()
    {
        base.HaveRest();
        battleState = StoryBattleState.Break;
    }
    protected void ReloadTeam()
    {
        battleObjMgr.ReloadTeam(TeamManager.Instance.GetTeam(TeamType.Story), BattleCamp.Red);
    }
    public override void OnBattleEnd(JsonData turnFightStateData)
    {
        base.OnBattleEnd(turnFightStateData);
    }
    // public override void Run()
Main/System/Battle/BattleHUDWin.cs
@@ -94,11 +94,8 @@
        damageContentList.Add(content);
        // heroGo 的 parent 作为参考节点
        var heroGo = bo.heroGo;
        if (heroGo == null)
            return;
        var heroRect = heroGo.GetComponent<RectTransform>();
        var heroRect = bo.heroRectTrans;
        if (heroRect == null)
            return;
Main/System/Battle/BattleManager.cs
@@ -3,6 +3,8 @@
using LitJson;
public class BattleManager : GameSystemManager<BattleManager>
{
    public StoryBattleField storyBattleField = null;
@@ -32,7 +34,7 @@
        ulong exAttr1 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr1);
        ulong exAttr2 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr2);
        int MapID = 0;
        int MapID = 1;
        int FuncLineID = (int)exAttr2;
        CreateStoryBattle(MapID, FuncLineID, null, null);
@@ -44,12 +46,17 @@
    {
        if (null == storyBattleField)
        {
            storyBattleField = new StoryBattleField();
            storyBattleField.guid = string.Empty; // 主线副本的guid为空
            var redTeamList = new List<TeamBase>();
            redTeamList.Add(TeamManager.Instance.GetTeam(TeamType.Story));
            storyBattleField.Init(MapID, FuncLineID, extendData, redTeamList, blueTeamList);
            TeamBase storyTeam = TeamManager.Instance.GetTeam(TeamType.Story);
            redTeamList.Add(storyTeam);
            CreateBattleField(string.Empty, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        }
        else
        {
            // storyBattleField
        }
    }
@@ -59,7 +66,7 @@
    }
#region 截断网络派发包 只收入当前包的后续 b425是主线的 非主线的包并不会走b425
    #region 截断网络派发包 只收入当前包的后续 b425是主线的 非主线的包并不会走b425
    private bool allow = true;
    private Queue<GameNetPackBasic> packQueue = new Queue<GameNetPackBasic>();
@@ -81,7 +88,7 @@
                //  发送战报片段结束包
                AnalysisPackQueueAndDistribute();
            }
        }
        else
@@ -95,25 +102,34 @@
        return allow;
    }
    protected int continousEmptyCount = 0; // 连续空包计数
    protected void AnalysisPackQueueAndDistribute()
    {
        // 建议前端做一个防范机制:当连续多次请求得到空的战斗片段封包时(不包含B425标记的开始跟结束封包,即开始跟中间没有任何封包),强制自动帮玩家回城休息,
        // 原因可能前后端数据不一致bug(比如战锤可能后端没有了,前端认为还有)或者 后端有bug导致没有处理战斗
        // 为防止死循环,可强制回城休息,让玩家重新点击关卡战斗或挑战boss,
        // 正常情况下在战锤足够时理论上都可以一直循环刷怪,如果连续多次没有战斗片段封包,比如限制个连续10次以内,就可以理解为异常了
        const int MaxContinousEmptyCount = 10; // 连续空包最大次数
        List<GameNetPackBasic> packQueueSnapshot = new List<GameNetPackBasic>(packQueue);
        List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>();
        //  这里已经是按照Dequeue的顺序了
        // 这里已经是按照Dequeue的顺序了
        for (int i = 0; i < packQueueSnapshot.Count; i++)
        {
            GameNetPackBasic pack = packQueueSnapshot[i];
            //  碰到B421 截断 往下收集b421里的全部内容
            // 碰到B421 截断 往下收集b421里的全部内容
            if (pack is HB421_tagMCTurnFightObjAction)
            {
                HB421_tagMCTurnFightObjAction b421Pack = pack as HB421_tagMCTurnFightObjAction;
                List<GameNetPackBasic> b421PackList = new List<GameNetPackBasic>();
                i++;    //  跳过当前的B421包
                i++;    // 跳过当前的B421包
                for (; i < packQueueSnapshot.Count; i++)
                {
@@ -131,7 +147,7 @@
                    }
                }
                //  可能没用了 主要就是利用一下skill的combine 暂留 看之后还有没有别的需求
                // 可能没用了 主要就是利用一下skill的combine 暂留 看之后还有没有别的需求
                CustomB421ActionPack actionPack = CustomB421ActionPack.CreateB421ActionPack(GetGUID(b421Pack.packUID), b421PackList);
                while (actionPack.actionPacks.Count > 0)
@@ -146,8 +162,26 @@
            }
        }
        // 防范机制:连续多次没有战斗片段封包时自动回城
        if (newPackList.Count == 0)
        {
            continousEmptyCount++;
            Debug.LogWarning($"连续空战斗片段封包次数:{continousEmptyCount}");
            if (continousEmptyCount >= MaxContinousEmptyCount)
            {
                Debug.LogError("连续多次没有战斗片段封包,自动回城休息!");
                MainFightRequest(0); // 0-停止战斗回城
                continousEmptyCount = 0;
                packQueue.Clear();
                return;
            }
        }
        else
        {
            continousEmptyCount = 0; // 有包就重置
        }
        //  b421跟b426的包已经处理完了
        // b421跟b426的包已经处理完了
        packQueue = new Queue<GameNetPackBasic>(newPackList);
        DistributeNextPackage();
@@ -189,9 +223,9 @@
        }
    }
#endregion
    #endregion
#region 战报部分
    #region 战报部分
    protected Dictionary<string, Queue<GameNetPackBasic>> battleReportDict = new Dictionary<string, Queue<GameNetPackBasic>>();
@@ -227,10 +261,6 @@
    {
        BattleField battleField = null;
        battleFields.TryGetValue(guid, out battleField);
        if (battleField == null)
        {
            battleField = storyBattleField;
        }
        return battleField;
    }
@@ -243,7 +273,7 @@
            if (kv.Value.Contains(packUID))
            {
                return kv.Key;
            }
            }
        }
        return string.Empty;
    }
@@ -267,7 +297,7 @@
            battlePackRelationList.Remove(guid);
        }
    }
#endregion
    #endregion
    public BattleField CreateBattleField(string guid, int MapID, int FuncLineID, JsonData extendData, List<TeamBase> redTeamList, List<TeamBase> blueTeamList)
    {
@@ -279,13 +309,11 @@
            battleField.Destroy();
        }
        battleField = BattleFieldFactory.CreateBattleField(guid, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        if (string.IsNullOrEmpty(guid))
        {
            battleField = storyBattleField;
        }
        else
        {
            battleField = BattleFieldFactory.CreateBattleField(guid, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
            storyBattleField = (StoryBattleField)battleField;
        }
        battleFields.Add(guid, battleField);
@@ -296,15 +324,28 @@
    }
    // public void OnTurnFightObjAction(battleType, vNetData.TurnNum, (int)vNetData.ObjID)
    // 目前支持  BYTE ReqType; // 0-停止战斗回城;1-设置消耗倍值;2-挑战关卡小怪;3-挑战关卡boss;4-继续战斗;
    // 0-停止战斗回城   -  玩家主动点击回城时发送
    // 1-设置消耗倍值   -  玩家设置消耗倍值,对应到玩家FightPoint的值
    // 2-挑战关卡小怪   -  玩家点击开始战斗时发送,仅从休息状态到开始战斗时发送即可
    // 3-挑战关卡boss   -  玩家请求挑战该关卡boss时发送
    // 4-继续战斗          -   玩家主线战斗中(包含主线小怪、主线boss),前端表现完后端同步的战斗片段后,可再回复该值,后端会根据战斗逻辑及流程自动回复下一段的战斗片段封包,一直循环
    public void MainFightRequest(byte reqType, uint reqValue = 0)
    {
        CB413_tagCSMainFightReq req = new CB413_tagCSMainFightReq();
        req.ReqType = reqType;
        req.ReqValue = reqValue;
        GameNetSystem.Instance.SendInfo(req);
    }
    public void Run()
    {
        if (null != storyBattleField)
        {
            storyBattleField.Run();
        }
        // if (null != storyBattleField)
        // {
        //     storyBattleField.Run();
        // }
        foreach (var battleField in battleFields)
        {
Main/System/Battle/BattleObject/BattleObjMgr.cs
@@ -19,10 +19,16 @@
    public void Init(BattleField _battleField, TeamBase _redTeam, TeamBase _blueTeam)
    {
        battleField = _battleField;
        CreateTeam(battleField.battleRootNode.redTeamNodeList, redCampDict, _redTeam, BattleCamp.Red);
        CreateTeam(battleField.battleRootNode.blueTeamNodeList, blueCampDict, _blueTeam, BattleCamp.Blue);
        ReloadTeam(_redTeam, BattleCamp.Red);
        ReloadTeam(_blueTeam, BattleCamp.Blue);
    }
    public void ReloadTeam(TeamBase teamBase, BattleCamp _camp)
    {
        var posNodeList = _camp == BattleCamp.Red ? battleField.battleRootNode.redTeamNodeList : battleField.battleRootNode.blueTeamNodeList;
        var campDict = _camp == BattleCamp.Red ? redCampDict : blueCampDict;
        CreateTeam(posNodeList, campDict, teamBase, _camp);
    }
    protected void CreateTeam(List<GameObject> posNodeList, Dictionary<int, BattleObject> campDict, TeamBase teamBase, BattleCamp _Camp)
    {
@@ -32,14 +38,14 @@
            return;
        }
        for (int i = 0; i < teamBase.serverHeroes.Length; i++)
        {
            TeamHero teamHero = teamBase.serverHeroes[i];
            if (teamHero != null)
            {
                BattleObject battleObj = BattleObjectFactory.CreateBattleObject(battleField, posNodeList, teamHero, _Camp);
                if (battleObj.ObjID == 0)
                    continue;
                allBattleObjDict.Add(battleObj.ObjID, battleObj);
                campDict.Add(teamHero.positionNum, battleObj);
            }
@@ -82,6 +88,36 @@
        return retList;
    }
    public void DestroyTeam(BattleCamp battleCamp)
    {
        Dictionary<int, BattleObject> campDict = battleCamp == BattleCamp.Red ? redCampDict : blueCampDict;
        if (campDict == null)
        {
            return;
        }
        DestroyTeam(campDict);
    }
    public void DestroyObjIds(uint[] objIDs)
    {
        if (objIDs == null || objIDs.Length == 0)
        {
            return;
        }
        foreach (var objID in objIDs)
        {
            if (allBattleObjDict.TryGetValue((int)objID, out BattleObject battleObj))
            {
                allBattleObjDict.Remove((int)objID);
                redCampDict.Remove((int)objID);
                blueCampDict.Remove((int)objID);
                BattleObjectFactory.DestroyBattleObject((int)objID, battleObj);
            }
        }
    }
    protected void DestroyTeam(Dictionary<int, BattleObject> campDict)
    {
        foreach (var item in campDict)
@@ -94,11 +130,10 @@
            }
        }
        campDict.Clear();
    }
    //  空闲状态
    public void HaveRest(BattleCamp _Camp)
    public virtual void HaveRest(BattleCamp _Camp)
    {
        //  休息状态
        if (_Camp == BattleCamp.Red)
@@ -117,7 +152,7 @@
        }
    }
    public void Release()
    public virtual void Release()
    {
        DestroyTeam(redCampDict);
        DestroyTeam(blueCampDict);
Main/System/Battle/BattleObject/BattleObject.cs
@@ -48,11 +48,27 @@
        private set;
    }
    private RectTransform m_heroRectTrans;
    public RectTransform heroRectTrans
    {
        get
        {
            if (m_heroRectTrans == null)
            {
                m_heroRectTrans = heroGo.GetComponent<RectTransform>();
            }
            return m_heroRectTrans;
        }
    }
    protected Action onDeathAnimationComplete;
    protected Renderer[] renderers;
    public Transform effectNode;
    private List<HB405_tagMCAddExp> hB405_tagMCAddExps = new List<HB405_tagMCAddExp>();
    public BattleObject(BattleField _battleField)
    {
@@ -92,17 +108,19 @@
    public virtual void Destroy()
    {
        if (heroGo != null)
        {
            GameObject.DestroyImmediate(heroGo);
            heroGo = null;
        }
        motionBase.onAnimationComplete -= OnAnimationComplete;
        motionBase.Release();
        motionBase = null;
        teamHero = null;
        ObjID = 0;
        motionBase.onAnimationComplete -= OnAnimationComplete;
        if (heroGo != null)
        {
            GameObject.DestroyImmediate(heroGo);
            heroGo = null;
        }
    }
    public void OnObjInfoRefresh(H0418_tagObjInfoRefresh _refreshInfo)
@@ -207,28 +225,21 @@
        return true;
    }
    public virtual void Hurt(List<long> damageValues, int attackType)
    public virtual void Hurt(List<long> damageValues, long _totalDamage, int attackType)
    {
        PopDamage(teamHero.curHp, damageValues, attackType);
        motionBase.PlayAnimation(MotionName.hit, false);
        //  计算伤害
        long totalDamage = 0;
        foreach (var damage in damageValues)
        {
            totalDamage += damage;
        }
        //  扣血
        teamHero.curHp -= totalDamage;
        teamHero.curHp -= _totalDamage;
    }
    //  闪避开始
    public virtual void OnDodgeBegin()
    {
        float pingpongTime = 0.2f;
        RectTransform rectTrans = heroGo.GetComponent<RectTransform>();
        RectTransform rectTrans = heroRectTrans;
        var tween = rectTrans.DOAnchorPos(new Vector3(-50, 50, 0), pingpongTime)
            .SetEase(Ease.OutCubic);
@@ -239,7 +250,7 @@
    public virtual void OnDodgeEnd()
    {
        float pingpongTime = 0.2f;
        RectTransform rectTrans = heroGo.GetComponent<RectTransform>();
        RectTransform rectTrans = heroRectTrans;
        var tween = rectTrans.DOAnchorPos(Vector3.zero, pingpongTime)
                            .SetEase(Ease.OutCubic);
@@ -269,6 +280,14 @@
        heroGo.SetActive(false);
    }
    public void OnReborn(HB423_tagMCTurnFightObjReborn vNetData)
    {
        // 处理复活逻辑
        teamHero.curHp = GeneralDefine.GetFactValue(vNetData.HP, vNetData.HPEx);
        heroGo.SetActive(true);
        motionBase.PlayAnimation(MotionName.idle, true);
    }
    // 伤害还要看 是否闪避 暴击 and so on 需要有一个DamageType 服务器应该会给
    protected virtual void PopDamage(long curHp, List<long> damageValues, int attackType)
    {
@@ -281,6 +300,7 @@
            Debug.Log($"Damage: {damage}");
        }
        // YYL TODO 是否需要挂在在自身的follow点上
        EventBroadcast.Instance.Broadcast(EventName.BATTLE_DAMAGE_TAKEN, battleField.guid, this, damageValues);
    }
@@ -304,8 +324,24 @@
        // YYL TODO
        //  休息状态
        //  多一个zzz的一个特效
        motionBase.PlayAnimation(MotionName.idle, true);
    }
    public void PushExpPackList(List<HB405_tagMCAddExp> _hB405_tagMCAddExps)
    {
        // YYL TODO 死亡后弹出经验掉落提醒
        hB405_tagMCAddExps = _hB405_tagMCAddExps;
    }
    public void DropExp()
    {
        // YYL TODO
        // hB405_tagMCAddExps
    }
#if UNITY_EDITOR_STOP_USING
    public void EditorRevive()
    {
Main/System/Battle/BattleTweenMgr.cs
@@ -51,4 +51,16 @@
        tween.Play();
    }
    public void HaveRest()
    {
        foreach (var tween in tweenList)
        {
            if (tween != null && !tween.IsComplete())
            {
                tween.Kill();
            }
        }
        tweenList.Clear();
    }
}
Main/System/Battle/BattleUtility.cs
@@ -29,4 +29,50 @@
            .OnComplete(() => onComplete?.Invoke());
    }
    public static string DisplayDamageNum(long num, int attackType)
    {
        var basePowerStr = UIHelper.ReplaceLargeArtNum(num);
        var result = string.Empty;
        for (int i = 0; i < basePowerStr.Length; i++)
        {
            var numChar = (char)GetDamageNumKey((DamageType)attackType, basePowerStr[i]);
            if (numChar > 0)
            {
                result += numChar;
            }
        }
        return result;
    }
    public static int GetDamageNumKey(DamageType damageType, int _num)
    {
        var config = DamageNumConfig.Get(damageType.ToString());
        //.的ASCII码是46
        if (_num == 46)
        {
            return config.nums[10];
        }
        //k的ASCII码是107
        else if (_num == 107)
        {
            return config.nums[11];
        }
        //m的ASCII码是109
        else if (_num == 109)
        {
            return config.nums[12];
        }
        //b的ASCII码是98
        else if (_num == 98)
        {
            return config.nums[13];
        }
        //t的ASCII码是116
        else if (_num == 116)
        {
            return config.nums[14];
        }
        return config.nums[_num - 48];
    }
}
Main/System/Battle/BattleWin.cs
@@ -23,13 +23,18 @@
    private void PauseGame()
    {
        Debug.LogError("PauseeGame");
        if (null == battleField)
            return;
        // Debug.LogError("PauseeGame");
        // if (null == battleField)
        //     return;
        battleField.IsPause = !battleField.IsPause;
        // battleField.IsPause = !battleField.IsPause;
        Debug.LogError(" is pause " + battleField.IsPause.ToString());
        // Debug.LogError(" is pause " + battleField.IsPause.ToString());
        if (battleField != null)
        {
            battleField.operationAgent.DoNext();
        }
    }
    protected override void OnPreOpen()
Main/System/Battle/Define/DamageType.cs
@@ -3,14 +3,16 @@
public enum DamageType
{
    Normal,    //普通伤害
    Dodge,     //闪避
    Heal,    //治疗
    Continuous,//持续伤害
    Block,    //格挡
    ReverseInjury,//反伤
    Recovery,    //吸血
    Crit,    //暴击
    Combo,    //连击
    Stuned,    //击晕
    Damage, //普通伤害
    Recovery,   //治疗
    Reflect, //反弹伤害
    Bloody, //流血伤害
    Block, //格挡
    Critical, //暴击
    Dodge, //闪避
    Combo, //连击
    CounterAttack, //反击
    RageUp, //怒气提升
}
Main/System/Battle/RecordPlayer/RecordPlayer.cs
@@ -73,4 +73,10 @@
    {
    }
    public void HaveRest()
    {
        currentRecordAction = null;
        recordActionQueue.Clear();
    }
}
Main/System/Battle/Skill/DirectlyDamageSkill.cs
@@ -64,9 +64,9 @@
        base.OnHitTargets(_hitIndex, hitList);
    }
    protected override void OnHitEachTarget(BattleObject target, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    protected override void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    {
        base.OnHitEachTarget(target, damageList, ref hurt);
        base.OnHitEachTarget(target, totalDamage, damageList, ref hurt);
    }
Main/System/Battle/Skill/DirectlyHealSkill.cs
New file
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
public class DirectlyHealSkill : SkillBase
{
    protected SkillEffect skillEffect;
    public DirectlyHealSkill(BattleObject _caster, SkillConfig _skillCfg,
            H0604_tagUseSkillAttack _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField)
            : base(_caster, _skillCfg, _vNetData, _packList, _battleField)
    {
        foreach (var pack in packList)
        {
            Debug.LogError("directly heal skill pack type is " + pack.GetType());
        }
    }
    public override void Run()
    {
        if (null != skillEffect)
        {
            skillEffect.Run();
        }
        base.Run();
    }
    //    技能动画播放完毕
    protected override void DoSkillLogic(Action _onComplete = null)
    {
        // if (skillConfig.EffectId > 0)
        // {
        //     // 播放技能特效
        //     caster.battleField.battleEffectMgr.PlayEffect(
        //         caster.ObjID,
        //         skillConfig.EffectId,
        //         caster.heroGo.transform
        //     );
        // }
        _onComplete?.Invoke();
    }
    //    前摇结束
    protected override void OnStartSkillFrame()
    {
        skillEffect = SkillEffectFactory.CreateSkillEffect(
                caster,
                skillConfig,
                tagUseSkillAttack
            );
        if (skillEffect != null)
        {
            skillEffect.Play(OnHitTargets);
        }
    }
    protected override void OnHitTargets(int _healIndex, List<H0604_tagUseSkillAttack.tagSkillHurtObj> healList)
    {
        base.OnHitTargets(_healIndex, healList);
    }
    protected override void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    {
        base.OnHitEachTarget(target, totalDamage, damageList, ref hurt);
    }
    //  中摇结束
    protected override void OnActiveSkillFrame()
    {
    }
    //    后摇结束
    protected override void OnEndSkillFrame()
    {
    }
}
Main/System/Battle/Skill/DirectlyHealSkill.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38e775dae78a7c9418366ae4f0f6514e
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/Skill/RebornSkill.cs
New file
@@ -0,0 +1,81 @@
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
public class RebornSkill : SkillBase
{
    protected SkillEffect skillEffect;
    public RebornSkill(BattleObject _caster, SkillConfig _skillCfg,
            H0604_tagUseSkillAttack _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField)
            : base(_caster, _skillCfg, _vNetData, _packList, _battleField)
    {
    }
    public override void Run()
    {
        if (null != skillEffect)
        {
            skillEffect.Run();
        }
        base.Run();
    }
    //    技能动画播放完毕
    protected override void DoSkillLogic(Action _onComplete = null)
    {
        // if (skillConfig.EffectId > 0)
        // {
        //     // 播放技能特效
        //     caster.battleField.battleEffectMgr.PlayEffect(
        //         caster.ObjID,
        //         skillConfig.EffectId,
        //         caster.heroGo.transform
        //     );
        // }
        _onComplete?.Invoke();
    }
    //    前摇结束
    protected override void OnStartSkillFrame()
    {
        skillEffect = SkillEffectFactory.CreateSkillEffect(
                caster,
                skillConfig,
                tagUseSkillAttack
            );
        if (skillEffect != null)
        {
            skillEffect.Play(OnHitTargets);
        }
    }
    protected override void OnHitTargets(int _hitIndex, List<H0604_tagUseSkillAttack.tagSkillHurtObj> hitList)
    {
        base.OnHitTargets(_hitIndex, hitList);
    }
    protected override void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    {
        base.OnHitEachTarget(target, totalDamage, damageList, ref hurt);
    }
    //  中摇结束
    protected override void OnActiveSkillFrame()
    {
    }
    //    后摇结束
    protected override void OnEndSkillFrame()
    {
    }
}
Main/System/Battle/Skill/RebornSkill.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88762e1ee728ecd45808b8759a3431ca
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/Skill/SkillBase.cs
@@ -29,6 +29,10 @@
    protected SkillBase otherSkill;
    protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>();
    protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>();
    public SkillBase(BattleObject _caster, SkillConfig _skillCfg, H0604_tagUseSkillAttack vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null)
    {
        caster = _caster;
@@ -88,7 +92,7 @@
                PlayCastAnimation(() => DoSkillLogic(OnSkillFinished));
                break;
            case SkillCastMode.Enemy:
                MoveToTarget(caster.GetEnemyCamp(), skillConfig.CastIndexNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                MoveToTarget(caster.GetEnemyCamp(), skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                break;
            case SkillCastMode.Target:
                // 目标是敌方主目标
@@ -99,10 +103,10 @@
                    OnSkillFinished();
                    return;
                }
                MoveToTarget(mainTarget.Camp, mainTarget.teamHero.positionNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                MoveToTarget(mainTarget.Camp, mainTarget, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                break;
            case SkillCastMode.Allies:
                MoveToTarget(caster.Camp, skillConfig.CastIndexNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                MoveToTarget(caster.Camp, skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                break;
            // case SkillCastMode.DashCast:
            //     DashToTarget(() => BackToOrigin(OnSkillFinished));
@@ -143,13 +147,24 @@
                OnActiveSkillFrame);//攻击中摇结束
    }
    public void MoveToTarget(BattleCamp camp, int index, float duration = 0.2f, Action _onComplete = null)
    public void MoveToTarget(BattleCamp camp, BattleObject target, float duration = 0.2f, Action _onComplete = null)
    {
        // GetTargetNode();
        targetNode = battleField.GetTeamNode(camp, index);
        targetNode = battleField.GetTeamNode(camp, target);
        Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
        RectTransform selfRect = caster.heroGo.transform as RectTransform;
        RectTransform selfRect = caster.heroRectTrans;
        RectTransform targetRect = targetNode;
        var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
        battleField.battleTweenMgr.OnPlayTween(tweener);
    }
    public void MoveToTarget(BattleCamp camp, SkillConfig skillCfg, float duration = 0.2f, Action _onComplete = null)
    {
        targetNode = battleField.GetTeamNode(camp, skillCfg);
        Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
        RectTransform selfRect = caster.heroRectTrans;
        RectTransform targetRect = targetNode;
        var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
@@ -168,7 +183,7 @@
    public void BackToOrigin(Action _onComplete = null)
    {
        RectTransform selfRect = caster.heroGo.transform as RectTransform;
        RectTransform selfRect = caster.heroRectTrans;
        Vector2 targetAnchoredPos = Vector2.zero;
        var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f)
            .SetEase(Ease.Linear)
@@ -187,7 +202,6 @@
        // 高亮所有目标
        HashSet<BattleObject> highlightList = new HashSet<BattleObject>(battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack));
        highlightList.Add(caster);
        
        //    把这些BO全高亮 或者说把除了这些的都放在遮罩后面
@@ -208,28 +222,50 @@
                continue;
            }
            // 伤害结算
            // 伤害分布 (万分比)
            int[] damageDivide = skillConfig.DamageDivide[_hitIndex];
            List<long> damageList = new List<long>();
            long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
            for (int j = 0; j < damageDivide.Length; j++)
            {
                long damage = totalDamage * damageDivide[j] / 10000;
                damageList.Add(damage);
            }
            // 保证所有分配项加起来等于totalDamage,避免因整除导致的误差
            List<long> damageList = DivideDamageToList(damageDivide, totalDamage);
            OnHitEachTarget(target, damageList, ref hurt);
            OnHitEachTarget(target, totalDamage, damageList, ref hurt);
        }
    }
    /// <summary>
    /// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差
    /// </summary>
    protected List<long> DivideDamageToList(int[] damageDivide, long totalDamage)
    {
        List<long> fixedDamageList = new List<long>();
        long assigned = 0;
        int count = damageDivide.Length;
        for (int i = 0; i < count; i++)
        {
            long damage;
            if (i == count - 1)
            {
                // 最后一个分配项修正为剩余
                damage = totalDamage - assigned;
            }
            else
            {
                damage = (totalDamage * damageDivide[i] + 5000) / 10000; // 四舍五入
                assigned += damage;
            }
            fixedDamageList.Add(damage);
        }
        return fixedDamageList;
    }
    protected virtual void OnHitEachTarget(BattleObject target, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    protected virtual void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    {
        target.Hurt(damageList, hurt.AttackType);
        target.Hurt(damageList, totalDamage, hurt.AttackType);
                //    击中目标的时候,不管近战远程 都确认一下是否有爆炸特效 然后播放
        //    击中目标的时候,不管近战远程 都确认一下是否有爆炸特效 然后播放
        if (skillConfig.ExplosionEffectId > 0)
        {
            // 播放爆炸特效
@@ -239,8 +275,160 @@
                target.heroGo.transform
            );
        }
        //    受伤之后辨别死亡状态 死亡包其实前后帧会多次触发 应该要即时remove其他的包来保证不重复
        if (target.IsDead())
        {
            // SkillRecordAction里的drop事件前移到dead之后
            HB422_tagMCTurnFightObjDead deadPack = FindDeadPack(target);
            CheckAfterDeadhPack(target, deadPack);
            if (deadPack != null)
            {
                //    处理掉落包
                for (int i = 0; i < dropPackList.Count; i++)
                {
                    PackageRegedit.Distribute(dropPackList[i]);
                }
                dropPackList.Clear();
                target.PushExpPackList(new List<HB405_tagMCAddExp>(expPackList));
                expPackList.Clear();
                // 处理死亡包
                PackageRegedit.Distribute(deadPack);
                packList.Remove(deadPack);
            }
            //    复活包暂时不管 可能是技能的包
            // HB423_tagMCTurnFightObjReborn rebornPack = FindRebornPack(target);
            // if (rebornPack != null)
            // {
            //     //    处理复活包
            //     PackageRegedit.Distribute(rebornPack);
            //     packList.Remove(rebornPack);
            // }
        }
    }
    protected HB423_tagMCTurnFightObjReborn FindRebornPack(BattleObject target)
    {
        HB423_tagMCTurnFightObjReborn rebornPack = null;
        for (int i = 0; i < packList.Count; i++)
        {
            var pack = packList[i];
            if (pack is HB423_tagMCTurnFightObjReborn)
            {
                rebornPack = pack as HB423_tagMCTurnFightObjReborn;
                if (rebornPack.ObjID == target.ObjID)
                {
                    return rebornPack;
                }
            }
            else if (pack is CustomHB426CombinePack)
            {
                var combinePack = pack as CustomHB426CombinePack;
                if (combinePack.startTag.Tag.StartsWith("Skill_"))
                {
                    break; // 找到技能包就不需要再处理了
                }
            }
        }
        return null;
    }
    protected HB422_tagMCTurnFightObjDead FindDeadPack(BattleObject target)
    {
        HB422_tagMCTurnFightObjDead deadPack = null;
        for (int i = 0; i < packList.Count; i++)
        {
            var pack = packList[i];
            //    寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包
            if (pack is HB422_tagMCTurnFightObjDead)
            {
                deadPack = pack as HB422_tagMCTurnFightObjDead;
                if (deadPack.ObjID == target.ObjID)
                {
                    return deadPack;
                }
            }
            else if (pack is CustomHB426CombinePack)
            {
                //    找死亡包不要越过技能包
                var combinePack = pack as CustomHB426CombinePack;
                if (combinePack.startTag.Tag.StartsWith("Skill_"))
                {
                    break;
                }
            }
        }
        return null;
    }
    protected void CheckAfterDeadhPack(BattleObject target, HB422_tagMCTurnFightObjDead deadPack)
    {
        if (null == deadPack)
        {
            return;
        }
        var deadPackIndex = packList.IndexOf(deadPack);
        if (deadPackIndex < 0)
        {
            return;
        }
        List<int> removeIndexList = new List<int>();
        for (int i = deadPackIndex + 1; 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()
    {
        return isFinished;
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -49,7 +49,7 @@
                    Debug.LogError("子弹的目标是自己,暂时不支持 协商程序完成");
                    break;
                case SkillCastMode.Enemy:
                    var targetNode = caster.battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig.CastIndexNum);
                    var targetNode = caster.battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig);
                    ShotToFormation(targetNode, onHitFormation);
                    break;
                case SkillCastMode.Target:
@@ -67,7 +67,7 @@
                    }
                    break;
                case SkillCastMode.Allies:
                    var healNode = caster.battleField.GetTeamNode(caster.Camp, skillConfig.CastIndexNum);
                    var healNode = caster.battleField.GetTeamNode(caster.Camp, skillConfig);
                    ShotToFormation(healNode, onHitFormation);
                    break;
                default:
@@ -116,7 +116,7 @@
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.effectNode);
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroGo.transform as RectTransform, tagUseSkillAttack, (index, hitList) =>
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroRectTrans, tagUseSkillAttack, (index, hitList) =>
        {
            //  击中就销毁子弹 子弹不需要自动销毁 配置表里autoDestroy为false
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
Main/System/KnapSack/Logic/ItemLogicUtility.cs
@@ -368,6 +368,41 @@
        }
    }
    /// <summary>
    /// <param name="packType 背包类型"></param>
    /// <param name="itemId 物品ID"></param>
    /// <param name="needCount 需要数量"></param>
    /// <param name="needTips 是否需要提示"></param>
    /// <returns></returns>
    public static bool CheckItemCount(PackType packType, int itemId, int needCount, bool needTips)
    {
        if (needCount <= 0)
        {
            return true;
        }
        int haveCount = PackManager.Instance.GetItemCountByID(packType, itemId);
        bool isEnough = haveCount >= needCount;
        if (!isEnough && needTips)
        {
            var itemConfig = ItemConfig.Get(itemId);
            if (null != itemConfig)
            {
                // SysNotifyMgr.Instance.ShowTip();
            }
        }
        return isEnough;
    }
    public static bool CheckCurrencyCount()
    {
        return true;
    }
    public event Action<string> GetBetterEquipEvent; //得到更好的装备 value 物品的实例ID
    // public void OnGetEquip(ItemModel item)
Main/System/Team/TeamManager.cs
@@ -1,12 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System;
public class TeamManager : GameSystemManager<TeamManager>
{
    protected Dictionary<TeamType, TeamBase> teamDict = new Dictionary<TeamType, TeamBase>();
    public Action<TeamType> OnTeamChange = null;
    public override void Init()
    {
@@ -29,9 +31,12 @@
    public void OnHeroChangeEvent(HB124_tagSCLineupInfo vNetData)
    {
        var heroPack = PackManager.Instance.GetSinglePack(PackType.Hero);
        HashSet<TeamType> teamTypeSet = new HashSet<TeamType>();
        for (int i = 0; i < vNetData.LineupCnt; i++)
        {
            var team = GetTeam((TeamType)vNetData.LineupList[i].LineupID);
            TeamType teamType = (TeamType)vNetData.LineupList[i].LineupID;
            teamTypeSet.Add(teamType);
            var team = GetTeam(teamType);
            for (int j = 0; j < vNetData.LineupList[i].HeroCnt; j++)
            {
                int index = vNetData.LineupList[i].HeroItemIndexList[j];
@@ -54,7 +59,12 @@
                team.RefreshServerData(vNetData.LineupList[i].ShapeType, j, hero);
            }
        }
    }
        foreach (var tt in teamTypeSet)
        {
            OnTeamChange?.Invoke(tt);
        }
    }
    public bool HasTeam(TeamType teamType)
Main/Utility/EnumHelper.cs
@@ -466,7 +466,7 @@
    GoldPaper = 19,                     //金票  19,
    Silver = 20,                       //银子 20,
    SilverPaper = 21,                  //银票    21,
    //FightPoint = 22,                   //战斗值  22,
    FightPoint = 22,                   //战斗值(锤子)  22,
    HappyPoint = 23,                   //娱乐值  23,
    MapID = 24,                        //角色所在地图  24,
    PosX = 25,                         //角色坐标 25,