yyl
2 天以前 d0dfe302f42f680bd3a84a29b9d58947046403c7
125 武将皮肤/技能皮肤 战斗部分
4个文件已添加
28个文件已修改
851 ■■■■■ 已修改文件
Main/Config/ConfigManager.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/SkillConfig.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/SkillSkinConfig.cs 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/SkillSkinConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/SkillConfig.Partial.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/SkillSkinConfig.Partial.cs 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/SkillSkinConfig.Partial.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObjectFactory.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/HeroBattleObject.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/MinggeBattleObject.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleResources/TeamResTracker.cs 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleUtility.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Buff/BattleObjectBuffMgr.cs 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Define/BattleDmgInfo.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Motion/MotionBase.cs 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillBase.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletSkillEffect.cs 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/DotSkillEffect.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/NoEffect.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/NormalSkillEffect.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffect.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffectFactory.cs 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigManager.cs
@@ -91,9 +91,9 @@
            typeof(PlayerAttrConfig),
            typeof(PlayerFaceConfig),
            typeof(PresetUnlockConfig),
            typeof(PriorBundleConfig),
            typeof(RandomNameConfig),
            typeof(SignInConfig),
            typeof(SkillSkinConfig),
            typeof(StoreConfig),
            typeof(SuccessConfig),
            typeof(SysInfoConfig),
@@ -364,12 +364,12 @@
        ClearConfigDictionary<PlayerFaceConfig>();
        // 清空 PresetUnlockConfig 字典
        ClearConfigDictionary<PresetUnlockConfig>();
        // 清空 PriorBundleConfig 字典
        ClearConfigDictionary<PriorBundleConfig>();
        // 清空 RandomNameConfig 字典
        ClearConfigDictionary<RandomNameConfig>();
        // 清空 SignInConfig 字典
        ClearConfigDictionary<SignInConfig>();
        // 清空 SkillSkinConfig 字典
        ClearConfigDictionary<SkillSkinConfig>();
        // 清空 StoreConfig 字典
        ClearConfigDictionary<StoreConfig>();
        // 清空 SuccessConfig 字典
Main/Config/Configs/SkillConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2025年12月12日
//    [  Date ]:           2026年2月7日
//--------------------------------------------------------
using System.Collections.Generic;
@@ -35,34 +35,10 @@
    public int[] BuffStateLimit;
    public int BuffState;
    public int FightPower;
    public string SkillMotionName;
    public string IconName;
    public string BuffIconName;
    public string SkillTipsName;
    public int EffectType;
    public int StartupFrames;
    public int[] ActiveFrames;
    public int RecoveryFrames;
    public int LoopCount;
    public int CastPosition;
    public int CastIndexNum;
    public float CastDistance;
    public int[][] DamageDivide;
    public int BulletEffectId;
    public int BulletPath;
    public float BulletFlySpeed;
    public int Scattering;
    public int ExplosionEffectId;
    public int ExplosionEffect2;
    public int ExplosionEffect3;
    public int ExplosionEffect4;
    public int EffectId;
    public int EffectId2;
    public int SkinllSFX1;
    public int SkinllSFX2;
    public int MStartEffectId;
    public int BuffEffect;
    public int TriggerEffect;
    public int ClientTriggerTiming;
    public override int LoadKey(string _key)
@@ -125,75 +101,15 @@
            int.TryParse(tables[18],out FightPower); 
            SkillMotionName = tables[19];
            IconName = tables[19];
            IconName = tables[20];
            BuffIconName = tables[20];
            BuffIconName = tables[21];
            SkillTipsName = tables[21];
            SkillTipsName = tables[22];
            int.TryParse(tables[22],out Scattering);
            int.TryParse(tables[23],out EffectType);
            int.TryParse(tables[24],out StartupFrames);
            if (tables[25].Contains("["))
            {
                ActiveFrames = JsonMapper.ToObject<int[]>(tables[25]);
            }
            else
            {
                string[] ActiveFramesStringArray = tables[25].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                ActiveFrames = new int[ActiveFramesStringArray.Length];
                for (int i=0;i<ActiveFramesStringArray.Length;i++)
                {
                     int.TryParse(ActiveFramesStringArray[i],out ActiveFrames[i]);
                }
            }
            int.TryParse(tables[26],out RecoveryFrames);
            int.TryParse(tables[27],out LoopCount);
            int.TryParse(tables[28],out CastPosition);
            int.TryParse(tables[29],out CastIndexNum);
            float.TryParse(tables[30],out CastDistance);
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[31].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[32],out BulletEffectId);
            int.TryParse(tables[33],out BulletPath);
            float.TryParse(tables[34],out BulletFlySpeed);
            int.TryParse(tables[35],out Scattering);
            int.TryParse(tables[36],out ExplosionEffectId);
            int.TryParse(tables[37],out ExplosionEffect2);
            int.TryParse(tables[38],out ExplosionEffect3);
            int.TryParse(tables[39],out ExplosionEffect4);
            int.TryParse(tables[40],out EffectId);
            int.TryParse(tables[41],out EffectId2);
            int.TryParse(tables[42],out SkinllSFX1);
            int.TryParse(tables[43],out SkinllSFX2);
            int.TryParse(tables[44],out MStartEffectId);
            int.TryParse(tables[45],out BuffEffect);
            int.TryParse(tables[46],out TriggerEffect);
            int.TryParse(tables[47],out ClientTriggerTiming);
            int.TryParse(tables[23],out ClientTriggerTiming);
        }
        catch (Exception exception)
        {
Main/Config/Configs/SkillSkinConfig.cs
New file
@@ -0,0 +1,122 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年2月7日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class SkillSkinConfig : ConfigBase<string, SkillSkinConfig>
{
    static SkillSkinConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public string SkillSkinID;
    public string SkillMotionName;
    public int EffectType;
    public int CastPosition;
    public int CastIndexNum;
    public float CastDistance;
    public int StartupFrames;
    public int[] ActiveFrames;
    public int RecoveryFrames;
    public int LoopCount;
    public int[][] DamageDivide;
    public int BulletEffectId;
    public int BulletPath;
    public float BulletFlySpeed;
    public int ExplosionEffectId;
    public int ExplosionEffect2;
    public int ExplosionEffect3;
    public int ExplosionEffect4;
    public int EffectId;
    public int EffectId2;
    public int SkinllSFX1;
    public int SkinllSFX2;
    public int MStartEffectId;
    public int BuffEffect;
    public int TriggerEffect;
    public override string LoadKey(string _key)
    {
        string key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        SkillSkinID = tables[0];
            SkillMotionName = tables[1];
            int.TryParse(tables[2],out EffectType);
            int.TryParse(tables[3],out CastPosition);
            int.TryParse(tables[4],out CastIndexNum);
            float.TryParse(tables[5],out CastDistance);
            int.TryParse(tables[6],out StartupFrames);
            if (tables[7].Contains("["))
            {
                ActiveFrames = JsonMapper.ToObject<int[]>(tables[7]);
            }
            else
            {
                string[] ActiveFramesStringArray = tables[7].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                ActiveFrames = new int[ActiveFramesStringArray.Length];
                for (int i=0;i<ActiveFramesStringArray.Length;i++)
                {
                     int.TryParse(ActiveFramesStringArray[i],out ActiveFrames[i]);
                }
            }
            int.TryParse(tables[8],out RecoveryFrames);
            int.TryParse(tables[9],out LoopCount);
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[10].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[11],out BulletEffectId);
            int.TryParse(tables[12],out BulletPath);
            float.TryParse(tables[13],out BulletFlySpeed);
            int.TryParse(tables[14],out ExplosionEffectId);
            int.TryParse(tables[15],out ExplosionEffect2);
            int.TryParse(tables[16],out ExplosionEffect3);
            int.TryParse(tables[17],out ExplosionEffect4);
            int.TryParse(tables[18],out EffectId);
            int.TryParse(tables[19],out EffectId2);
            int.TryParse(tables[20],out SkinllSFX1);
            int.TryParse(tables[21],out SkinllSFX2);
            int.TryParse(tables[22],out MStartEffectId);
            int.TryParse(tables[23],out BuffEffect);
            int.TryParse(tables[24],out TriggerEffect);
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/SkillSkinConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16994c332e272e048a0ce72b27c91aaf
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/PartialConfigs/SkillConfig.Partial.cs
@@ -21,9 +21,8 @@
    public static readonly int[] DebuffSkillType = new int[] { 4, 6, 14 };
    public SkillType skillType;
    public SkillCastMode castMode;
    public SkillEffectType effectType;
    protected SkillSkinConfig originSkinConfig;
    //技能类型:技能等级:技能
    static Dictionary<int, Dictionary<int, SkillConfig>> skillDics = new Dictionary<int, Dictionary<int, SkillConfig>>();
@@ -32,24 +31,6 @@
        base.OnConfigParseCompleted();
        skillType = (SkillType)SkillType;
        castMode = (SkillCastMode)CastPosition;
        effectType = (SkillEffectType)EffectType;
        if (DamageDivide == null || DamageDivide.Length == 0)
        {
            DamageDivide = new int[1][];
            DamageDivide[0] = new int[] { 10000 };
        }
        // #if UNITY_EDITOR
        //         if (Launch.Instance.isOpenBattleDebug)
        //         {
        //             if (castMode == SkillCastMode.None)
        //             {
        //                 castMode = SkillCastMode.Target;
        //             }
        //         }
        // #endif
        Dictionary<int, SkillConfig> tempDic = null;
        if (!skillDics.TryGetValue((int)skillType, out tempDic))
@@ -58,6 +39,39 @@
            skillDics.Add((int)skillType, tempDic);
        }
        tempDic[SkillLV] = this;
    }
    public SkillSkinConfig GetSkillSkinConfig(int skinID)
    {
        string key = skinID.ToString() + SkillID.ToString();
        SkillSkinConfig skillSkinConfig = SkillSkinConfig.Get(key);
        if (null == skillSkinConfig)
        {
            return GetOriginSkinConfig();
        }
        else
        {
            return skillSkinConfig;
        }
    }
    public SkillSkinConfig GetOriginSkinConfig()
    {
        if (originSkinConfig == null)
        {
            originSkinConfig = SkillSkinConfig.Get(SkillID.ToString());
        }
        if (null == originSkinConfig)
        {
            Debug.LogError("找不到技能皮肤配置 " + SkillID);
            return null;
        }
        else
        {
            return originSkinConfig;
        }
    }
    public bool IsGainBuff()
@@ -69,11 +83,6 @@
    {
        return Array.Exists(DebuffSkillType, type => type == (int)skillType);
    }
    public MotionName GetMotionName()
    {
        return Enum.Parse<MotionName>(SkillMotionName);
    }
    public static SkillConfig GetSkillConfig(int skillType, int skillLv)
    {
@@ -87,25 +96,5 @@
        return config;
    }
    public List<int> GetDamageDivide(int _hitIndex)
    {
        List<int> damageDivide = new List<int>();
        if (_hitIndex == 0 && DamageDivide.Length <= 0)
        {
            damageDivide.Add(10000);
        }
        else
        {
            if (DamageDivide.Length <= _hitIndex)
            {
                Debug.LogError("技能伤害分布配置错误 skillId: " + SkillID + " hitIndex: " + _hitIndex);
                damageDivide.Add(10000);
            }
            else
            {
                damageDivide = DamageDivide[_hitIndex].ToList();
            }
        }
        return damageDivide;
    }
}
Main/Config/PartialConfigs/SkillSkinConfig.Partial.cs
New file
@@ -0,0 +1,64 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年2月7日
//--------------------------------------------------------
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System;
using UnityEngine;
using LitJson;
using System.Linq;
public partial class SkillSkinConfig : ConfigBase<string, SkillSkinConfig>
{
    public SkillCastMode castMode;
    public SkillEffectType effectType;
    protected override void OnConfigParseCompleted()
    {
        base.OnConfigParseCompleted();
        castMode = (SkillCastMode)CastPosition;
        effectType = (SkillEffectType)EffectType;
        if (DamageDivide == null || DamageDivide.Length == 0)
        {
            DamageDivide = new int[1][];
            DamageDivide[0] = new int[] { 10000 };
        }
    }
    public MotionName GetMotionName()
    {
        return Enum.Parse<MotionName>(SkillMotionName);
    }
    public List<int> GetDamageDivide(int _hitIndex)
    {
        List<int> damageDivide = new List<int>();
        if (_hitIndex == 0 && DamageDivide.Length <= 0)
        {
            damageDivide.Add(10000);
        }
        else
        {
            if (DamageDivide.Length <= _hitIndex)
            {
                Debug.LogError("技能伤害分布配置错误 SkillSkinID: " + SkillSkinID + " hitIndex: " + _hitIndex);
                damageDivide.Add(10000);
            }
            else
            {
                damageDivide = DamageDivide[_hitIndex].ToList();
            }
        }
        return damageDivide;
    }
}
Main/Config/PartialConfigs/SkillSkinConfig.Partial.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e0292b891c625c45985eefa582a2463
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -417,7 +417,8 @@
        if (hB427_TagSCUseSkill != null)
        {
            SkillConfig scCfg = SkillConfig.Get((int)hB427_TagSCUseSkill.SkillID);
            if (!string.IsNullOrEmpty(scCfg.SkillMotionName))
            SkillSkinConfig skillSkinConfig = scCfg.GetOriginSkinConfig();
            if (!string.IsNullOrEmpty(skillSkinConfig.SkillMotionName))
            {
                needWaiting = true;
                return needWaiting;
@@ -437,7 +438,8 @@
            if (pack is HB427_tagSCUseSkill skillPack && skillPack != hB427_TagSCUseSkill)
            {
                SkillConfig ssc = SkillConfig.Get((int)skillPack.SkillID);
                if (!string.IsNullOrEmpty(ssc.SkillMotionName))
                SkillSkinConfig skillSkinConfig = ssc.GetOriginSkinConfig();
                if (!string.IsNullOrEmpty(skillSkinConfig.SkillMotionName))
                {
                    needWaiting = true;
                    break;
Main/System/Battle/BattleField/BattleField.cs
@@ -632,9 +632,9 @@
        return GetTeamNode(battleCamp, index);
    }
    public RectTransform GetTeamNode(BattleCamp battleCamp, SkillConfig skillConfig)
    public RectTransform GetTeamNode(BattleCamp battleCamp, SkillSkinConfig skillSkinConfig)
    {
        int index = skillConfig.CastIndexNum - 1; // 技能配置的index是从1开始的,所以要减1
        int index = skillSkinConfig.CastIndexNum - 1; // 技能配置的index是从1开始的,所以要减1
        return GetTeamNode(battleCamp, index);
    }
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs
@@ -175,7 +175,7 @@
        if (isCast)
            return;
        if (skillBase.caster.CanCastSkillAnimation(skillBase.skillConfig))
        if (skillBase.caster.CanCastSkillAnimation(skillBase.skillSkinConfig))
        {
            // Debug.LogError("cast skill id is " + skillBase.skillConfig.SkillID);
Main/System/Battle/BattleObject/BattleObject.cs
@@ -93,7 +93,7 @@
    /// <summary>
    /// 播放技能动画
    /// </summary>
    public abstract Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, bool isCounter, Action onComplete);
    public abstract Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, bool isCounter, Action onComplete);
    
    /// <summary>
    /// 检查是否可以开始死亡
@@ -103,7 +103,7 @@
    /// <summary>
    /// 检查是否可以释放技能
    /// </summary>
    public abstract bool CanCastSkillAnimation(SkillConfig skillConfig);
    public abstract bool CanCastSkillAnimation(SkillSkinConfig skillSkinConfig);
    
    /// <summary>
    /// 获取骨骼动画组件(用于特效挂载等)
@@ -405,7 +405,7 @@
        }
        // ============ 应用施法者的血量和护盾变化 ============
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1;
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillSkinConfig.DamageDivide.Length - 1;
        ApplyHurtToCaster(battleHurtParam, isLastHit);
        // 和Hurt一样,调用PopDamage处理吸血/反伤的显示
Main/System/Battle/BattleObject/BattleObjectFactory.cs
@@ -42,6 +42,9 @@
            Debug.LogError($"BattleObjectFactory: Failed to load SkeletonDataAsset for {skinCfg.SpineRes}");
            return null;
        }
        Debug.LogError($"{teamHero.SkinID} : {skinCfg.SpineRes}");
        // ==============================================
        GameObject battleGO = ResManager.Instance.LoadAsset<GameObject>("Hero/SpineRes", "Hero_001"/*skinCfg.SpineRes*/);
Main/System/Battle/BattleObject/HeroBattleObject.cs
@@ -186,9 +186,9 @@
        }
    }
    
    public override Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, bool isCounter, Action onComplete)
    public override Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, bool isCounter, Action onComplete)
    {
        return motionBase.PlaySkillAnimation(skillConfig, skillBase, isCounter, onComplete);
        return motionBase.PlaySkillAnimation(skillConfig, skillSkinConfig, skillBase, isCounter, onComplete);
    }
    
    public override bool CanStartDeath()
@@ -196,9 +196,9 @@
        return motionBase.CanStartDeath();
    }
    
    public override bool CanCastSkillAnimation(SkillConfig skillConfig)
    public override bool CanCastSkillAnimation(SkillSkinConfig skillSkinConfig)
    {
        return motionBase.CanCastSkill(skillConfig);
        return motionBase.CanCastSkill(skillSkinConfig);
    }
    
    public override SkeletonAnimation GetSkeletonAnimation()
@@ -339,7 +339,7 @@
    public override DeathRecordAction Hurt(BattleHurtParam battleHurtParam, SkillRecordAction _parentSkillAction = null)
    {
        DeathRecordAction recordAction = null;
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1;
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillSkinConfig.DamageDivide.Length - 1;
        bool firstHit = battleHurtParam.hitIndex == 0;
        
        // 添加调试日志
@@ -704,7 +704,7 @@
        }
        // ============ 应用施法者的血量和护盾变化 ============
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1;
        bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillSkinConfig.DamageDivide.Length - 1;
        ApplyHurtToCaster(battleHurtParam, isLastHit);
        // 和Hurt一样,调用PopDamage处理吸血/反伤的显示
Main/System/Battle/BattleObject/MinggeBattleObject.cs
@@ -106,11 +106,11 @@
        // 命格没有幻影
    }
    
    public override Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, bool isCounter, Action onComplete)
    public override Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, bool isCounter, Action onComplete)
    {
        // 命格没有技能动画,立即触发所有帧事件
        int loopCount = skillConfig.LoopCount + 1; //默认会有一次
        int frameCount = skillConfig.ActiveFrames.Length;
        int loopCount = skillSkinConfig.LoopCount + 1; //默认会有一次
        int frameCount = skillSkinConfig.ActiveFrames.Length;
        
        // 1. 技能开始
        skillBase.OnSkillStart();
@@ -150,7 +150,7 @@
        return false;
    }
    
    public override bool CanCastSkillAnimation(SkillConfig skillConfig)
    public override bool CanCastSkillAnimation(SkillSkinConfig skillSkinConfig)
    {
        // 命格总是可以释放技能(从动画角度)
        return true;
Main/System/Battle/BattleResources/TeamResTracker.cs
@@ -71,56 +71,69 @@
        // 普攻技能
        if (teamHero.heroConfig.AtkSkillID > 0)
        {
            AddSingleSkillResources(teamHero.heroConfig.AtkSkillID, info, isPersistent, ownerId);
            SkillConfig skillConfig = SkillConfig.Get(teamHero.heroConfig.AtkSkillID);
            if (null != skillConfig)
            {
                SkillSkinConfig skillSkinConfig = skillConfig.GetSkillSkinConfig(teamHero.SkinID);
                if (null != skillSkinConfig)
                {
                    AddSingleSkillResources(skillSkinConfig, info, isPersistent, ownerId);
                }
            }
        }
        
        // 怒气技能
        if (teamHero.heroConfig.AngerSkillID > 0)
        {
            AddSingleSkillResources(teamHero.heroConfig.AngerSkillID, info, isPersistent, ownerId);
            SkillConfig skillConfig = SkillConfig.Get(teamHero.heroConfig.AngerSkillID);
            if (null != skillConfig)
            {
                SkillSkinConfig skillSkinConfig = skillConfig.GetSkillSkinConfig(teamHero.SkinID);
                if (null != skillSkinConfig)
                {
                    AddSingleSkillResources(skillSkinConfig, info, isPersistent, ownerId);
                }
            }
        }
    }
    
    /// <summary>
    /// 添加单个技能的资源
    /// </summary>
    private static void AddSingleSkillResources(int skillId, TeamResourceInfo info, bool isPersistent, string ownerId)
    private static void AddSingleSkillResources(SkillSkinConfig skillSkinConfig, TeamResourceInfo info, bool isPersistent, string ownerId)
    {
        SkillConfig skillConfig = SkillConfig.Get(skillId);
        if (skillConfig == null)
            return;
        
        AddSkillAudio(skillConfig, info, isPersistent, ownerId);
        AddSkillEffects(skillConfig, info, isPersistent, ownerId);
        AddSkillAudio(skillSkinConfig, info, isPersistent, ownerId);
        AddSkillEffects(skillSkinConfig, info, isPersistent, ownerId);
    }
    
    private static void AddSkillAudio(SkillConfig skillConfig, TeamResourceInfo info, bool isPersistent, string ownerId)
    private static void AddSkillAudio(SkillSkinConfig skillSkinConfig, TeamResourceInfo info, bool isPersistent, string ownerId)
    {
        if (skillConfig.SkinllSFX1 > 0)
        if (skillSkinConfig.SkinllSFX1 > 0)
        {
            AddAudioResource(skillConfig.SkinllSFX1, info, isPersistent, ownerId);
            AddAudioResource(skillSkinConfig.SkinllSFX1, info, isPersistent, ownerId);
        }
        
        if (skillConfig.SkinllSFX2 > 0)
        if (skillSkinConfig.SkinllSFX2 > 0)
        {
            AddAudioResource(skillConfig.SkinllSFX2, info, isPersistent, ownerId);
            AddAudioResource(skillSkinConfig.SkinllSFX2, info, isPersistent, ownerId);
        }
    }
    
    private static void AddSkillEffects(SkillConfig skillConfig, TeamResourceInfo info, bool isPersistent, string ownerId)
    private static void AddSkillEffects(SkillSkinConfig skillSkinConfig, TeamResourceInfo info, bool isPersistent, string ownerId)
    {
        List<int> effectIds = new List<int>();
        
        if (skillConfig.BulletEffectId > 0) effectIds.Add(skillConfig.BulletEffectId);
        if (skillConfig.ExplosionEffectId > 0) effectIds.Add(skillConfig.ExplosionEffectId);
        if (skillConfig.ExplosionEffect2 > 0) effectIds.Add(skillConfig.ExplosionEffect2);
        if (skillConfig.ExplosionEffect3 > 0) effectIds.Add(skillConfig.ExplosionEffect3);
        if (skillConfig.ExplosionEffect4 > 0) effectIds.Add(skillConfig.ExplosionEffect4);
        if (skillConfig.EffectId > 0) effectIds.Add(skillConfig.EffectId);
        if (skillConfig.EffectId2 > 0) effectIds.Add(skillConfig.EffectId2);
        if (skillConfig.MStartEffectId > 0) effectIds.Add(skillConfig.MStartEffectId);
        if (skillConfig.BuffEffect > 0) effectIds.Add(skillConfig.BuffEffect);
        if (skillConfig.TriggerEffect > 0) effectIds.Add(skillConfig.TriggerEffect);
        if (skillSkinConfig.BulletEffectId > 0) effectIds.Add(skillSkinConfig.BulletEffectId);
        if (skillSkinConfig.ExplosionEffectId > 0) effectIds.Add(skillSkinConfig.ExplosionEffectId);
        if (skillSkinConfig.ExplosionEffect2 > 0) effectIds.Add(skillSkinConfig.ExplosionEffect2);
        if (skillSkinConfig.ExplosionEffect3 > 0) effectIds.Add(skillSkinConfig.ExplosionEffect3);
        if (skillSkinConfig.ExplosionEffect4 > 0) effectIds.Add(skillSkinConfig.ExplosionEffect4);
        if (skillSkinConfig.EffectId > 0) effectIds.Add(skillSkinConfig.EffectId);
        if (skillSkinConfig.EffectId2 > 0) effectIds.Add(skillSkinConfig.EffectId2);
        if (skillSkinConfig.MStartEffectId > 0) effectIds.Add(skillSkinConfig.MStartEffectId);
        if (skillSkinConfig.BuffEffect > 0) effectIds.Add(skillSkinConfig.BuffEffect);
        if (skillSkinConfig.TriggerEffect > 0) effectIds.Add(skillSkinConfig.TriggerEffect);
        
        foreach (int effectId in effectIds)
        {
Main/System/Battle/BattleUtility.cs
@@ -379,24 +379,25 @@
    {
        long suckHp = GetSuckHp(skillBase.tagUseSkillAttack);
        SkillConfig skillConfig = skillBase.skillConfig;
        SkillSkinConfig skillSkinConfig = skillBase.skillSkinConfig;
        long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
        long totalReflectHp = hurt.BounceHP;
        // 计算伤害分段
        long currentHitDamage = 0;
        List<long> damageList = DivideDamageToList(skillConfig.DamageDivide, hitIndex, totalDamage, ref currentHitDamage);
        List<long> damageList = DivideDamageToList(skillSkinConfig.DamageDivide, hitIndex, totalDamage, ref currentHitDamage);
        // 计算吸血分段
        long currentHitSuckHp = 0;
        List<long> suckHpList = bSuckHp ? 
            DivideDamageToList(skillConfig.DamageDivide, hitIndex, suckHp, ref currentHitSuckHp) : new List<long>();
            DivideDamageToList(skillSkinConfig.DamageDivide, hitIndex, suckHp, ref currentHitSuckHp) : new List<long>();
        // 计算反伤分段
        long currentHitReflectHp = 0;
        List<long> reflectHpList = DivideDamageToList(skillConfig.DamageDivide, hitIndex, totalReflectHp, ref currentHitReflectHp);
        List<long> reflectHpList = DivideDamageToList(skillSkinConfig.DamageDivide, hitIndex, totalReflectHp, ref currentHitReflectHp);
        // 创建目标受伤对象
        BattleHurtObj hurter = CreateHurter(target, damageList, hurt, hitIndex, skillConfig, currentHitDamage);
        BattleHurtObj hurter = CreateHurter(target, damageList, hurt, hitIndex, skillSkinConfig, currentHitDamage);
        // 创建施法者对象
        BattleCastObj caster = CreateCaster(skillBase, suckHpList, reflectHpList, currentHitSuckHp, currentHitReflectHp);
@@ -411,11 +412,12 @@
        battleHurtParam.hitIndex = hitIndex;
        battleHurtParam.deadPack = deadPack;
        battleHurtParam.skillConfig = skillConfig;
        battleHurtParam.skillSkinConfig = skillSkinConfig;
        battleHurtParam.packUID = skillBase.tagUseSkillAttack.packUID;
        return battleHurtParam;
    }
    public static BattleHurtObj CreateHurter(BattleObject target, List<long> damageList, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, int hitIndex, SkillConfig skillConfig, long currentHitDamage)
    public static BattleHurtObj CreateHurter(BattleObject target, List<long> damageList, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, int hitIndex, SkillSkinConfig skillSkinConfig, long currentHitDamage)
    {
        BattleHurtObj hurter = new BattleHurtObj();
        hurter.hurtObj = target;
@@ -425,7 +427,7 @@
        hurter.fromShieldValue = buffMgr != null ? buffMgr.GetShieldValue() : 0; // 命格没有护盾
        // 判断是否是最后一击
        bool isLastHit = hitIndex >= skillConfig.DamageDivide.Length - 1;
        bool isLastHit = hitIndex >= skillSkinConfig.DamageDivide.Length - 1;
        
        // 判断是治疗还是伤害
        bool isHealing = IsHealing(hurt);
@@ -729,6 +731,7 @@
                    {
                        var skillID = hB427_TagSCUseSkill.SkillID;
                        var skillConfig = SkillConfig.Get((int)skillID);
                        var skillSkinConfig = skillConfig.GetOriginSkinConfig();
                        if (null == skillConfig)
                        {
Main/System/Battle/Buff/BattleObjectBuffMgr.cs
@@ -101,6 +101,7 @@
        {
            HB428_tagSCBuffRefresh buffData = null;
            bool isRemove = false;
            if (buffDataDict.TryGetValue(tempvNetData.BuffID, out buffData))
@@ -114,22 +115,38 @@
                return;
            }
            BattleObject buffCaster = battleObject.battleField.battleObjMgr.GetBattleObject((int)buffData.OwnerID);
            if (null == buffCaster)
            {
                Debug.LogError("找不到buff caster 对象 id is " + buffData.OwnerID + " buff id is " + tempvNetData.BuffID + " pack uid is " + vNetData.packUID);
            }
            bool isRemoveEffect = false;
            int remainCnt = -1;
            if (buffData != null)
            if (buffData != null && buffCaster != null)
            {
                SkillConfig skillConfig = SkillConfig.Get((int)buffData.SkillID);
                SkillSkinConfig skillSkinConfig = null;
                if (buffCaster is HeroBattleObject heroBattleObject)
                {
                    skillSkinConfig = skillConfig.GetSkillSkinConfig(heroBattleObject.teamHero.SkinID);
                }
                else
                {
                    skillSkinConfig = skillConfig.GetOriginSkinConfig();
                }
                if (null == skillConfig || skillConfig.BuffEffect <= 0)
                if (null == skillConfig || skillSkinConfig.BuffEffect <= 0)
                {
                    return;
                }
                KeyValuePair<BattleEffectPlayer, HashSet<uint>> effectPair;
                if (buffEffectDict.TryGetValue(skillConfig.BuffEffect, out effectPair))
                if (buffEffectDict.TryGetValue(skillSkinConfig.BuffEffect, out effectPair))
                {
                    effectPair.Value.Remove(buffData.BuffID);
@@ -139,8 +156,8 @@
                    {
                        //  没有这个buff了
                        isRemoveEffect = true;
                        battleObject.battleField.battleEffectMgr.RemoveEffect(skillConfig.BuffEffect, effectPair.Key);
                        buffEffectDict.Remove(skillConfig.BuffEffect);
                        battleObject.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BuffEffect, effectPair.Key);
                        buffEffectDict.Remove(skillSkinConfig.BuffEffect);
                    }
                }
@@ -276,22 +293,41 @@
        if (battleObject.IsDead())
            return;
        if (skillConfig.BuffEffect > 0)
        BattleObject buffCaster = battleObject.battleField.battleObjMgr.GetBattleObject((int)buffRefresh.OwnerID);
        if (null == buffCaster)
        {
            if (buffEffectDict.TryGetValue(skillConfig.BuffEffect, out var pair))
            Debug.LogError("找不到buff caster 对象 id is " + buffRefresh.OwnerID + " buff id is " + buffRefresh.BuffID + " pack uid is " + buffRefresh.packUID);
        }
        SkillSkinConfig skillSkinConfig = null;
        if (buffCaster is HeroBattleObject heroBattleObject)
        {
            skillSkinConfig = skillConfig.GetSkillSkinConfig(heroBattleObject.teamHero.SkinID);
        }
        else
        {
            skillSkinConfig = skillConfig.GetOriginSkinConfig();
        }
        if (skillSkinConfig.BuffEffect > 0)
        {
            if (buffEffectDict.TryGetValue(skillSkinConfig.BuffEffect, out var pair))
            {
                pair.Value.Add(buffRefresh.BuffID);
            }
            else
            {
                BattleEffectPlayer effect = battleObject.battleField.battleEffectMgr
                    .PlayEffect(battleObject, skillConfig.BuffEffect, battleObject.GetRectTransform(), battleObject.Camp, battleObject.GetModelScale());
                    .PlayEffect(battleObject, skillSkinConfig.BuffEffect, battleObject.GetRectTransform(), battleObject.Camp, battleObject.GetModelScale());
                effect.BindBone(battleObject, effect.effectConfig.nodeName);
                var buffIdSet = new HashSet<uint> { buffRefresh.BuffID };
                buffEffectDict.Add(
                    skillConfig.BuffEffect,
                    skillSkinConfig.BuffEffect,
                    new KeyValuePair<BattleEffectPlayer, HashSet<uint>>(effect, buffIdSet));
            }
        }
Main/System/Battle/Define/BattleDmgInfo.cs
@@ -91,7 +91,7 @@
        this.battleFieldGuid = battleFieldGuid;
        this.battleHurtParam = battleHurtParam;
        this.isCasterView = _isCasterView;
        this.isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1;
        this.isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillSkinConfig.DamageDivide.Length - 1;
        this.isFirstHit = battleHurtParam.hitIndex == 0;
        
        m_rawAttackType = hurt == null ? 0 : hurt.AttackTypes;
@@ -605,6 +605,7 @@
    public int hitIndex;
    public BattleDeadPack deadPack;
    public SkillConfig skillConfig;
    public SkillSkinConfig skillSkinConfig;
    public ulong packUID;
}
Main/System/Battle/Motion/MotionBase.cs
@@ -160,7 +160,7 @@
        return true;
    }
    public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, bool isSubSkill, Action onComplete = null)
    public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, bool isSubSkill, Action onComplete = null)
    {
        if (skillConfig == null)
        {
@@ -174,35 +174,35 @@
        }
        // 如果没有动画名称,使用无动画模式
        if (string.IsNullOrEmpty(skillConfig.SkillMotionName))
        if (string.IsNullOrEmpty(skillSkinConfig.SkillMotionName))
        {
            PlaySkillNoAnim(skillConfig, skillBase, onComplete, isSubSkill);
            PlaySkillNoAnim(skillConfig, skillSkinConfig, skillBase, onComplete, isSubSkill);
            return null;
        }
        Spine.Animation targetAnim = FindAnim(skillConfig.SkillMotionName);
        Spine.Animation targetAnim = FindAnim(skillSkinConfig.SkillMotionName);
        if (targetAnim == null)
        {
            skillBase.ForceFinished();
            return null;
        }
        return ExecuteSkillAnim(skillConfig, skillBase, onComplete, targetAnim, true, isSubSkill);
        return ExecuteSkillAnim(skillConfig, skillSkinConfig, skillBase, onComplete, targetAnim, true, isSubSkill);
    }
    private Spine.TrackEntry ExecuteSkillAnim(SkillConfig skillConfig, SkillBase skillBase, Action onComplete,
    private Spine.TrackEntry ExecuteSkillAnim(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, Action onComplete,
        Spine.Animation targetAnim, bool hasAnim, bool isSubSkill)
    {
        int loopCount = skillConfig.LoopCount;
        int loopCount = skillSkinConfig.LoopCount;
        //  前摇
        int startupFrames = skillConfig.StartupFrames;
        int startupFrames = skillSkinConfig.StartupFrames;
        //  中摇
        int[] activeFrames = skillConfig.ActiveFrames ?? new int[0];
        int[] activeFrames = skillSkinConfig.ActiveFrames ?? new int[0];
        int frameCount = activeFrames.Length;
        //  后摇
        float recoveryFrame = skillConfig.RecoveryFrames;
        float recoveryFrame = skillSkinConfig.RecoveryFrames;
        // 如果前中后摇没有配置 那么默认给一个1 2 3的帧数
        if (startupFrames <= 0 && frameCount == 0 && recoveryFrame <= 0f)
@@ -227,7 +227,7 @@
            {
                // 轨道池耗尽或未初始化,回退到无动画模式
                Debug.LogWarning($"子技能轨道池已满或未初始化,技能{skillConfig.SkillID}使用无动画模式");
                PlaySkillNoAnim(skillConfig, skillBase, onComplete, isSubSkill);
                PlaySkillNoAnim(skillConfig, skillSkinConfig, skillBase, onComplete, isSubSkill);
                return null;
            }
        }
@@ -244,7 +244,7 @@
                {
                    if (skillBase != null && !skillBase.IsFinished())
                    {
                        PlaySkillAnimation(skillConfig, skillBase, isSubSkill, onComplete);
                        PlaySkillAnimation(skillConfig, skillSkinConfig, skillBase, isSubSkill, onComplete);
                    }
                });
                return null;
@@ -405,13 +405,13 @@
            }
            // 各阶段回调(原有逻辑)
            if (!beginTriggered && currentFrame >= skillConfig.StartupFrames && currentLoop == 0)
            if (!beginTriggered && currentFrame >= skillSkinConfig.StartupFrames && currentLoop == 0)
            {
                beginTriggered = true;
                skillBase.OnStartSkillFrameEnd();
            }
            if (!middleStarted && currentFrame >= skillConfig.StartupFrames && currentLoop <= loopCount)
            if (!middleStarted && currentFrame >= skillSkinConfig.StartupFrames && currentLoop <= loopCount)
            {
                middleStarted = true;
                skillBase.OnMiddleFrameStart(currentLoop);
@@ -440,12 +440,12 @@
                    {
                        if (hasAnim)
                        {
                            skillTrack.TrackTime = skillConfig.StartupFrames / BattleConst.skillMotionFps;
                            skillTrack.TrackTime = skillSkinConfig.StartupFrames / BattleConst.skillMotionFps;
                        }
                        else
                        {
                            // 为下一 loop 重置 startTime,并且更新 pausedAccumulatedAtStart(以保持基线)
                            startTime = Time.time - (skillConfig.StartupFrames / BattleConst.skillMotionFps);
                            startTime = Time.time - (skillSkinConfig.StartupFrames / BattleConst.skillMotionFps);
                            pausedAccumulatedAtStart = pausedAccumulated;
                        }
                    }
@@ -538,8 +538,8 @@
        return targetAnim;
    }
    private void PlaySkillNoAnim(SkillConfig skillConfig, SkillBase skillBase, Action onComplete, bool isSubSkill) =>
        ExecuteSkillAnim(skillConfig, skillBase, onComplete, null, false, isSubSkill);
    private void PlaySkillNoAnim(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, Action onComplete, bool isSubSkill) =>
        ExecuteSkillAnim(skillConfig, skillSkinConfig, skillBase, onComplete, null, false, isSubSkill);
    protected virtual void SetupAnimationHandlers()
    {
@@ -748,9 +748,9 @@
        }
    }
    public bool CanCastSkill(SkillConfig skillConfig)
    public bool CanCastSkill(SkillSkinConfig skillSkinConfig)
    {
        return !playingSkillWithAnim || string.IsNullOrEmpty(skillConfig.SkillMotionName);
        return !playingSkillWithAnim || string.IsNullOrEmpty(skillSkinConfig.SkillMotionName);
    }
    public bool CanStartDeath()
Main/System/Battle/Skill/SkillBase.cs
@@ -19,6 +19,8 @@
    protected SkillEffect skillEffect;
    public HB427_tagSCUseSkill tagUseSkillAttack;
    public SkillConfig skillConfig;
    public SkillSkinConfig skillSkinConfig;
    protected bool isFinished = false;
    protected BattleField battleField = null; // 战场
    protected RectTransform targetNode = null; // 目标节点
@@ -57,6 +59,21 @@
        tagUseSkillAttack = vNetData;
        battleField = _battleField;
        packList = _packList;
        if (_caster is HeroBattleObject heroBattleObject)
        {
            skillSkinConfig = skillConfig.GetSkillSkinConfig(heroBattleObject.teamHero.SkinID);
            if (null == skillSkinConfig)
            {
                Debug.LogError("找不到技能皮肤表 " + "skillId: " + skillConfig.SkillID + " skinId: " + heroBattleObject.teamHero.SkinID);
            }
        }
        else
        {
            skillSkinConfig = skillConfig.GetOriginSkinConfig();
        }
        // 注册正在释放的技能
        if (battleField != null && caster != null)
@@ -249,9 +266,9 @@
        // 命格释放技能时 teamHero 为 null,监听器会正确处理(已有 null 检查)
        EventBroadcast.Instance.Broadcast<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, guid, skillConfig, teamHero);
        if (skillConfig.SkinllSFX1 != 0)
        if (skillSkinConfig.SkinllSFX1 != 0)
        {
            battleField.soundManager.PlayEffectSound(skillConfig.SkinllSFX1, false);
            battleField.soundManager.PlayEffectSound(skillSkinConfig.SkinllSFX1, false);
        }
        if (caster != null)
@@ -280,7 +297,7 @@
        HighLightAllTargets();
        // 根据释放模式执行相应逻辑
        switch (skillConfig.castMode)
        switch (skillSkinConfig.castMode)
        {
            case SkillCastMode.None:
            case SkillCastMode.Self:
@@ -299,7 +316,7 @@
                DashCast(OnAttackFinish);
                break;
            default:
                Debug.LogError("强制结束技能 暂时不支持其他的方式释放 有需求please联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition);
                Debug.LogError("强制结束技能 暂时不支持其他的方式释放 有需求please联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillSkinConfig.CastPosition);
                ForceFinished();
                break;
        }
@@ -323,7 +340,7 @@
    // 对敌方释放技能:移动到敌方区域进行攻击
    protected void CastToEnemy()
    {
        RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig);
        RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillSkinConfig);
        ExecuteMoveAndCastSequence(target, () =>
        {
            if (skillConfig.ClientTriggerTiming == 1)
@@ -371,7 +388,7 @@
    // 对友方释放技能:移动到友方区域进行治疗或增益
    protected void CastToAllies()
    {
        RectTransform target = battleField.GetTeamNode(caster.Camp, skillConfig);
        RectTransform target = battleField.GetTeamNode(caster.Camp, skillSkinConfig);
        ExecuteMoveAndCastSequence(target, () =>
        {
            if (skillConfig.ClientTriggerTiming == 1)
@@ -394,11 +411,11 @@
    private void ExecuteMoveAndCastSequence(RectTransform target, Action onReturnComplete)
    {
        ShadowIllutionCreate(true);
        MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), () =>
        MoveToTarget(target, new Vector2(skillSkinConfig.CastDistance, 0), () =>
        {
            if (skillConfig.CastDistance < 9999 && skillConfig.SkinllSFX2 != 0)
            if (skillSkinConfig.CastDistance < 9999 && skillSkinConfig.SkinllSFX2 != 0)
            {
                battleField.soundManager.PlayEffectSound(skillConfig.SkinllSFX2, false);
                battleField.soundManager.PlayEffectSound(skillSkinConfig.SkinllSFX2, false);
            }
            TurnBack(() =>
@@ -427,7 +444,7 @@
    // 移动到目标位置:处理角色的移动动画和逻辑
    protected void MoveToTarget(RectTransform target, Vector2 offset, Action _onComplete = null, float speed = 750f)
    {
        if (skillConfig.CastDistance >= 9999)
        if (skillSkinConfig.CastDistance >= 9999)
        {
            _onComplete?.Invoke();
            return;
@@ -445,7 +462,7 @@
    // 转身逻辑:根据技能配置处理角色转向
    protected void TurnBack(Action _onComplete, float forward)
    {
        if (skillConfig.CastDistance < 0)
        if (skillSkinConfig.CastDistance < 0)
        {
            caster.SetFacing(forward);
        }
@@ -476,7 +493,7 @@
    // 执行技能释放动画和逻辑:播放施法动作并提供回调
    protected TrackEntry CastImpl(Action onComplete = null)
    {
        return caster.PlaySkillAnimation(skillConfig, this, tagUseSkillAttack.BattleType == 4, onComplete);
        return caster.PlaySkillAnimation(skillConfig, skillSkinConfig, this, tagUseSkillAttack.BattleType == 4, onComplete);
    }
    // 技能开始回调:处理死亡、子技能、技能效果初始化
@@ -494,7 +511,7 @@
        //  再处理 内嵌技能
        ProcessSubSkill();
        skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, tagUseSkillAttack);
        skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, skillSkinConfig, tagUseSkillAttack);
        skillEffect.Play(OnHitTargets);
        
@@ -513,7 +530,8 @@
            if (pack is HB427_tagSCUseSkill skillPack)
            {
                SkillConfig ssc = SkillConfig.Get((int)skillPack.SkillID);
                if (!string.IsNullOrEmpty(ssc.SkillMotionName))
                SkillSkinConfig sscSkin = ssc.GetOriginSkinConfig();
                if (!string.IsNullOrEmpty(sscSkin.SkillMotionName))
                {
                    break;
                }
@@ -533,8 +551,8 @@
            {
                HB427_tagSCUseSkill sp = combinePack.GetMainHB427SkillPack();
                SkillConfig ssc = SkillConfig.Get((int)sp.SkillID);
                if (!string.IsNullOrEmpty(ssc.SkillMotionName))
                SkillSkinConfig sscSkin = ssc.GetOriginSkinConfig();
                if (!string.IsNullOrEmpty(sscSkin.SkillMotionName))
                {
                    break;
                }
@@ -883,7 +901,7 @@
#if UNITY_EDITOR
    private void PrintHurtParamDebugInfo(BattleHurtParam hurtParam)
    {
        bool isLastHit = hurtParam.hitIndex >= hurtParam.skillConfig.DamageDivide.Length - 1;
        bool isLastHit = hurtParam.hitIndex >= hurtParam.skillSkinConfig.DamageDivide.Length - 1;
        
        long currentHitDamage = hurtParam.hurter.damageList != null ? hurtParam.hurter.damageList.Sum() : 0;
        long currentHitSuckHp = hurtParam.caster.suckHpList != null ? hurtParam.caster.suckHpList.Sum() : 0;
@@ -898,7 +916,7 @@
            $"攻击者: {hurtParam.caster.casterObj.GetName()} (ObjID:{hurtParam.caster.casterObj.ObjID})\n" +
            $"目标: {hurtParam.hurter.hurtObj.GetName()} (ObjID:{hurtParam.hurter.hurtObj.ObjID})\n" +
            $"技能: {hurtParam.skillConfig.SkillName} (ID:{hurtParam.skillConfig.SkillID})\n" +
            $"击数: 第{hurtParam.hitIndex + 1}击 / 共{hurtParam.skillConfig.DamageDivide.Length}击" + (isLastHit ? " [最后一击]" : " [中间击]") + "\n" +
            $"击数: 第{hurtParam.hitIndex + 1}击 / 共{hurtParam.skillSkinConfig.DamageDivide.Length}击" + (isLastHit ? " [最后一击]" : " [中间击]") + "\n" +
            $"\n" +
            $"========== 目标受伤数据 ==========\n" +
            $"伤害: {currentHitDamage} / 总伤害: {totalDamage}\n" +
@@ -1204,7 +1222,7 @@
        if (moveFinished)
        {
            //  如果技能有动画(SkillMotionName不为空),需要等待动画播放完成
            if (skillConfig != null && !string.IsNullOrEmpty(skillConfig.SkillMotionName))
            if (skillSkinConfig != null && !string.IsNullOrEmpty(skillSkinConfig.SkillMotionName))
            {
                if (!isMotionCompleted)
                {
@@ -1608,7 +1626,7 @@
            return false;
        }
        if (string.IsNullOrEmpty(skillConfig.SkillMotionName))
        if (string.IsNullOrEmpty(skillSkinConfig.SkillMotionName))
        {
            return true;
        }
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs
@@ -8,16 +8,16 @@
    private Vector2 end;
    private Vector2 control;
    public BezierBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer,
    public BezierBulletCurve(BattleObject caster, SkillConfig skillConfig, SkillSkinConfig _skillSkinConfig, BattleEffectPlayer effectPlayer,
        RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, effectPlayer, target, hurtList, bulletIndex, onHit) { }
        : base(caster, skillConfig, _skillSkinConfig, effectPlayer, target, hurtList, bulletIndex, onHit) { }
    public override void Reset()
    {
        base.Reset();
        start = WorldToLocalAnchoredPosition(bulletTrans.position) + bulletOffset;
        end = WorldToLocalAnchoredPosition(target.position);
        duration = Vector2.Distance(start, end) / skillConfig.BulletFlySpeed;
        duration = Vector2.Distance(start, end) / skillSkinConfig.BulletFlySpeed;
        control = (start + end) / 2 + Vector2.up * 100f;
    }
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs
@@ -14,9 +14,9 @@
    private float bounceTime = 0.2f; // 每次弹射时间
    private float bounceElapsed = 0f;
    public BounceBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer,
    public BounceBulletCurve(BattleObject caster, SkillConfig skillConfig, SkillSkinConfig _skillSkinConfig, BattleEffectPlayer effectPlayer,
        RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, effectPlayer, target, hurtList, bulletIndex, onHit)
        : base(caster, skillConfig, _skillSkinConfig, effectPlayer, target, hurtList, bulletIndex, onHit)
    {
        this.hurtList = hurtList;
    }
@@ -30,7 +30,7 @@
        {
            start = WorldToLocalAnchoredPosition(bulletTrans.position) + bulletOffset;
            end = WorldToLocalAnchoredPosition(target.position);
            duration = Vector2.Distance(start, end) / skillConfig.BulletFlySpeed;
            duration = Vector2.Distance(start, end) / skillSkinConfig.BulletFlySpeed;
        }
    }
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs
@@ -7,6 +7,8 @@
{
    protected BattleObject caster;
    protected SkillConfig skillConfig;
    protected SkillSkinConfig skillSkinConfig;
    protected BattleEffectPlayer bulletEffect;
    protected RectTransform bulletTrans; // 子弹的RectTransform
    protected RectTransform target;
@@ -22,11 +24,12 @@
    protected List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurts = new List<HB427_tagSCUseSkill.tagSCUseSkillHurt>();
    public BulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target,
    public BulletCurve(BattleObject caster, SkillConfig skillConfig, SkillSkinConfig _skillSkinConfig, BattleEffectPlayer bulletEffect, RectTransform target,
        List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
    {
        this.caster = caster;
        this.skillConfig = skillConfig;
        skillSkinConfig = _skillSkinConfig;
        this.bulletEffect = bulletEffect;
        this.target = target;
        this.onHit = onHit;
@@ -82,7 +85,7 @@
    {
        finished = true;
        onHit?.Invoke(mBulletIndex, hurts);
        caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, bulletEffect);
        caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, bulletEffect);
    }
    public virtual void ForceFinish()
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs
@@ -13,6 +13,7 @@
    public static BulletCurve CreateBulletCurve(
        BattleObject caster,
        SkillConfig skillConfig,
        SkillSkinConfig _skillSkinConfig,
        BattleEffectPlayer bulletEffect,
        RectTransform target,
        List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList,
@@ -20,22 +21,22 @@
        Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
    {
        BulletCurve curve = null;
        switch (skillConfig.BulletPath)
        switch (_skillSkinConfig.BulletPath)
        {
            case 1: // 直线消失于目标
                curve = new StraightBulletCurve(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                curve = new StraightBulletCurve(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                break;
            case 2: // 直线贯穿消失在屏幕外
                curve = new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                curve = new PenetrateBulletCurve(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                break;
            case 3: // 抛物线弧线
                curve = new BezierBulletCurve(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                curve = new BezierBulletCurve(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                break;
            case 4: // 弹射
                curve = new BounceBulletCurve(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                curve = new BounceBulletCurve(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                break;
            default:
                curve = new BulletCurve(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                curve = new BulletCurve(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit);
                break;
        }
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs
@@ -9,8 +9,8 @@
    private Vector2 outPos;     // 屏幕外延长点(本地坐标)
    private bool hitTriggered = false; // 是否已触发onHit
    public PenetrateBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, effectPlayer, target, hurtList, bulletIndex, onHit) { }
    public PenetrateBulletCurve(BattleObject caster, SkillConfig skillConfig, SkillSkinConfig _skillSkinConfig, BattleEffectPlayer effectPlayer, RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, _skillSkinConfig, effectPlayer, target, hurtList, bulletIndex, onHit) { }
    /// <summary>
    /// 初始化弹道参数
@@ -21,7 +21,7 @@
        hitTriggered = false;
        start = WorldToLocalAnchoredPosition(bulletTrans.position) + bulletOffset;
        end = WorldToLocalAnchoredPosition(target.position);
        duration = Vector2.Distance(start, end) / skillConfig.BulletFlySpeed;
        duration = Vector2.Distance(start, end) / skillSkinConfig.BulletFlySpeed;
        Vector2 dir = (end - start).normalized;
        float extend = 500f; // 贯穿距离,可根据需求调整
        outPos = end + dir * extend;
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs
@@ -7,8 +7,8 @@
    private Vector2 start;
    private Vector2 end;
    public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, bulletEffect, target, hurtList, bulletIndex, onHit)
    public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, SkillSkinConfig _skillSkinConfig, BattleEffectPlayer bulletEffect, RectTransform target, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurtList, int bulletIndex, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, _skillSkinConfig, bulletEffect, target, hurtList, bulletIndex, onHit)
    {
    }
@@ -18,7 +18,7 @@
        base.Reset();
        start = WorldToLocalAnchoredPosition(bulletTrans.position) + bulletOffset;
        end = WorldToLocalAnchoredPosition(target.position);
        duration = Vector2.Distance(start, end) / skillConfig.BulletFlySpeed;
        duration = Vector2.Distance(start, end) / skillSkinConfig.BulletFlySpeed;
        // BattleUtility.MarkStartAndEnd(bulletTrans, target);
    }
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -18,8 +18,8 @@
    private int scatterTotalTargets = 0;
    public BulletSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _caster, _tagUseSkillAttack)
    public BulletSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _skillSkinConfig, _caster, _tagUseSkillAttack)
    {
    }
@@ -30,7 +30,7 @@
    {
        base.OnMiddleFrameEnd(times, index);
        //  弹射 另外的做法了
        if (skillConfig.effectType == SkillEffectType.Bullet && skillConfig.BulletPath == 4)
        if (skillSkinConfig.effectType == SkillEffectType.Bullet && skillSkinConfig.BulletPath == 4)
        {
            var hurt = tagUseSkillAttack.HurtList[0];
            BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
@@ -172,22 +172,22 @@
    private void ShotToIndex(BattleCamp camp, int targetIndex, int bulletIndex)
    {
        RectTransform targetTransform = caster.battleField.GetTeamNode(camp, targetIndex);
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, targetTransform, tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, targetTransform, tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        {
            if (isFinish)
                return;
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
            // 播放子弹爆炸特效
            BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
            //  首先是目标身上爆炸
            PlayExplosionEffect(skillConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
            PlayExplosionEffect(skillConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
            PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
            PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
            foreach (var hurt in hitList)
            {
@@ -198,8 +198,8 @@
                    continue;
                }
                PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
            }
            // 表现子弹飞行到目标位置
@@ -307,7 +307,7 @@
        {
            scatterHitCount = 0;
            // 总击中数 = 发射次数 × 目标数量
            scatterTotalTargets = skillConfig.ActiveFrames.Length * tagUseSkillAttack.HurtList.Length;
            scatterTotalTargets = skillSkinConfig.ActiveFrames.Length * tagUseSkillAttack.HurtList.Length;
        }
        
        // 处理散射逻辑
@@ -328,7 +328,7 @@
    private void ScatterShot(BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, int bulletIndex, int order)
    {
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        bool shotToSelf = target.ObjID == caster.ObjID;
@@ -336,7 +336,7 @@
        var tempOrder = order;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.GetRectTransform(),
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, target.GetRectTransform(),
            new List<HB427_tagSCUseSkill.tagSCUseSkillHurt> { hurt }, bulletIndex, (index, hitList) =>
        {
            foreach (var hurt in hitList)
@@ -348,16 +348,16 @@
                    continue;
                }
                PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
            }
            // 表现子弹飞行到目标位置
            onHit?.Invoke(index, hitList);
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
            // 增加散射击中计数
            scatterHitCount++;
@@ -374,7 +374,7 @@
    protected void ShotToTarget(BattleObject target, int bulletIndex)
    {
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        bool shotToSelf = target.ObjID == caster.ObjID;
@@ -384,9 +384,9 @@
        int tempBulletIndex = bulletIndex;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.GetRectTransform(), tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, target.GetRectTransform(), tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        {
            if (skillConfig.BulletPath == 4)
            if (skillSkinConfig.BulletPath == 4)
            {
                if (bounceHitIndex >= hitList.Count)
                {
@@ -396,10 +396,10 @@
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj != null)
                {
                    PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                }
                else
                {
@@ -411,13 +411,13 @@
                if (bounceHitIndex >= tagUseSkillAttack.HurtList.Length)
                {
                    caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
                    caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
                }
                if (isFinish)
                    return;
                if (tempBulletIndex >= skillConfig.ActiveFrames.Length - 1 && bounceHitIndex >= hitList.Count)
                if (tempBulletIndex >= skillSkinConfig.ActiveFrames.Length - 1 && bounceHitIndex >= hitList.Count)
                {
                    isFinish = true;
                }
@@ -433,22 +433,22 @@
                        continue;
                    }
                    PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                }
                // 表现子弹飞行到目标位置
                onHit?.Invoke(index, hitList);
                // 击中就销毁子弹
                caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
                caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
                if (isFinish)
                    return;
                if (bulletIndex >= skillConfig.ActiveFrames.Length - 1)
                if (bulletIndex >= skillSkinConfig.ActiveFrames.Length - 1)
                {
                    isFinish = true;
                }
Main/System/Battle/SkillEffect/DotSkillEffect.cs
@@ -13,8 +13,8 @@
    // protected BattleObject caster;
    // protected List<BattleObject> targets; // 目标列表
    public DotSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _caster, _tagUseSkillAttack)
    public DotSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _skillSkinConfig, _caster, _tagUseSkillAttack)
    {
    }
@@ -31,7 +31,7 @@
                Debug.LogError($"DotSkillEffect 找不到目标,GUID={hurtInfo.ObjID}");
                continue;
            }
            target.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.TriggerEffect, target.GetRectTransform(), caster.Camp, target.GetModelScale());
            target.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.TriggerEffect, target.GetRectTransform(), caster.Camp, target.GetModelScale());
        }
        onHit?.Invoke(0, tagUseSkillAttack.HurtList.ToList());
Main/System/Battle/SkillEffect/NoEffect.cs
@@ -13,8 +13,8 @@
    // protected BattleObject caster;
    // protected List<BattleObject> targets; // 目标列表
    public NoEffect(SkillBase _skillBase, SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _caster, _tagUseSkillAttack)
    public NoEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _skillSkinConfig, _caster, _tagUseSkillAttack)
    {
    }
@@ -28,14 +28,14 @@
        RectTransform targetTransform = caster.battleField.GetTeamNode(battleCamp, mainTargetIndex);
        if (skillConfig.ExplosionEffectId > 0)
        if (skillSkinConfig.ExplosionEffectId > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
        }
        if (skillConfig.ExplosionEffect2 > 0)
        if (skillSkinConfig.ExplosionEffect2 > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
        }
        for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
@@ -48,13 +48,13 @@
                continue;
            }
            if (skillConfig.ExplosionEffect3 > 0)
            if (skillSkinConfig.ExplosionEffect3 > 0)
            {
                caster.battleField.battleEffectMgr.PlayEffect(target, skillConfig.ExplosionEffect3, target.GetTransform(), caster.Camp, target.GetModelScale());
                caster.battleField.battleEffectMgr.PlayEffect(target, skillSkinConfig.ExplosionEffect3, target.GetTransform(), caster.Camp, target.GetModelScale());
            }
            if (skillConfig.ExplosionEffect4 > 0)
            if (skillSkinConfig.ExplosionEffect4 > 0)
            {
                caster.battleField.battleEffectMgr.PlayEffect(target, skillConfig.ExplosionEffect4, target.GetTransform(), caster.Camp, target.GetModelScale());
                caster.battleField.battleEffectMgr.PlayEffect(target, skillSkinConfig.ExplosionEffect4, target.GetTransform(), caster.Camp, target.GetModelScale());
            }
        }
Main/System/Battle/SkillEffect/NormalSkillEffect.cs
@@ -11,8 +11,8 @@
    // protected BattleObject caster;
    // protected List<BattleObject> targets; // 目标列表
    public NormalSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _caster, _tagUseSkillAttack)
    public NormalSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _skillSkinConfig, _caster, _tagUseSkillAttack)
    {
    }
@@ -27,14 +27,14 @@
        RectTransform targetTransform = caster.battleField.GetTeamNode(battleCamp, mainTargetIndex);
        if (skillConfig.ExplosionEffectId > 0)
        if (skillSkinConfig.ExplosionEffectId > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
        }
        if (skillConfig.ExplosionEffect2 > 0)
        if (skillSkinConfig.ExplosionEffect2 > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
        }
        for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
@@ -47,13 +47,13 @@
                continue;
            }
            if (skillConfig.ExplosionEffect3 > 0)
            if (skillSkinConfig.ExplosionEffect3 > 0)
            {
                caster.battleField.battleEffectMgr.PlayEffect(target, skillConfig.ExplosionEffect3, target.GetTransform(), caster.Camp, target.GetModelScale());
                caster.battleField.battleEffectMgr.PlayEffect(target, skillSkinConfig.ExplosionEffect3, target.GetTransform(), caster.Camp, target.GetModelScale());
            }
            if (skillConfig.ExplosionEffect4 > 0)
            if (skillSkinConfig.ExplosionEffect4 > 0)
            {
                caster.battleField.battleEffectMgr.PlayEffect(target, skillConfig.ExplosionEffect4, target.GetTransform(), caster.Camp, target.GetModelScale());
                caster.battleField.battleEffectMgr.PlayEffect(target, skillSkinConfig.ExplosionEffect4, target.GetTransform(), caster.Camp, target.GetModelScale());
            }
        }
Main/System/Battle/SkillEffect/SkillEffect.cs
@@ -6,6 +6,7 @@
{
    protected SkillBase skillBase;
    protected SkillConfig skillConfig;
    protected SkillSkinConfig skillSkinConfig;
    protected BattleObject caster;
    protected HB427_tagSCUseSkill tagUseSkillAttack;// 目标列表
@@ -15,10 +16,11 @@
    protected Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit;
    public SkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
    public SkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
    {
        skillBase = _skillBase;
        skillConfig = _skillConfig;
        skillSkinConfig = _skillSkinConfig;
        caster = _caster;
        tagUseSkillAttack = _tagUseSkillAttack;
    }
@@ -27,13 +29,13 @@
    public virtual void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit)
    {
        onHit = _onHit;
        if (skillConfig.EffectId > 0)
        if (skillSkinConfig.EffectId > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.EffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.EffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        }
        if (skillConfig.EffectId2 > 0)
        if (skillSkinConfig.EffectId2 > 0)
        {
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.EffectId2, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
            caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.EffectId2, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        }
     }
@@ -49,10 +51,10 @@
    public virtual void OnMiddleFrameStart(int times)
    {
        if (skillConfig.MStartEffectId <= 0)
        if (skillSkinConfig.MStartEffectId <= 0)
            return;
        //  中摇固定特效
        caster.battleField.battleEffectMgr.PlayEffect(caster, skillConfig.MStartEffectId, caster.GetTransform(), caster.Camp, caster.GetModelScale());
        caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.MStartEffectId, caster.GetTransform(), caster.Camp, caster.GetModelScale());
    }
    
    /// <summary>
Main/System/Battle/SkillEffect/SkillEffectFactory.cs
@@ -4,27 +4,27 @@
public static class SkillEffectFactory
{
    public static SkillEffect CreateSkillEffect(SkillBase skillBase, BattleObject caster, SkillConfig skillConfig, HB427_tagSCUseSkill tagUseSkillAttack)
    public static SkillEffect CreateSkillEffect(SkillBase skillBase, BattleObject caster, SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, HB427_tagSCUseSkill tagUseSkillAttack)
    {
        switch (skillConfig.effectType)
        switch (skillSkinConfig.effectType)
        {
            case SkillEffectType.Bullet:
                return new BulletSkillEffect(skillBase,skillConfig, caster, tagUseSkillAttack);
                return new BulletSkillEffect(skillBase,skillConfig, skillSkinConfig, caster, tagUseSkillAttack);
            case SkillEffectType.Direct:
                return new NormalSkillEffect(skillBase, skillConfig, caster, tagUseSkillAttack);
                return new NormalSkillEffect(skillBase, skillConfig, skillSkinConfig, caster, tagUseSkillAttack);
            // case SkillEffectType.BuffEffect:
            //     return new BuffSkillEffect(skillConfig, caster, targets);
            // case SkillEffectType.StageEffect:
            //     return new StageSkillEffect(skillConfig, caster, targets);
            case SkillEffectType.DOTEffect:
                return new DotSkillEffect(skillBase,skillConfig, caster, tagUseSkillAttack);
                return new DotSkillEffect(skillBase,skillConfig, skillSkinConfig, caster, tagUseSkillAttack);
            case SkillEffectType.NoEffect:
            case SkillEffectType.None:
                return new NoEffect(skillBase, skillConfig, caster, tagUseSkillAttack);
                return new NoEffect(skillBase, skillConfig, skillSkinConfig, caster, tagUseSkillAttack);
            default:
                UnityEngine.Debug.LogError("Unknown Skill Effect Type " + skillConfig.effectType + " skill id is " + skillConfig.SkillID);
                return new NoEffect(skillBase, skillConfig, caster, tagUseSkillAttack);
                UnityEngine.Debug.LogError("Unknown Skill Effect Type " + skillSkinConfig.effectType + " skill id is " + skillConfig.SkillID);
                return new NoEffect(skillBase, skillConfig, skillSkinConfig, caster, tagUseSkillAttack);
                break;
        }
        return null;