using System.Collections.Generic; using UnityEngine; public class BattleDmg { public long damage; public int attackType; public bool IsType(DamageType damageType) { return (attackType & (int)damageType) == (int)damageType; } } public class BattleDmgInfo { public string battleFieldGuid { get; private set; } public BattleHurtParam battleHurtParam { get; private set; } private bool isCasterView = false; // 标记是否是施法者视角 // 新增属性:自动判断是处理目标还是施法者 public List damageList { get { // 施法者视角:使用吸血和反伤列表的总和 if (isCasterView) { List casterDamages = new List(); if (battleHurtParam.caster?.suckHpList != null) casterDamages.AddRange(battleHurtParam.caster.suckHpList); if (battleHurtParam.caster?.reflectHpList != null) casterDamages.AddRange(battleHurtParam.caster.reflectHpList); return casterDamages; } // 目标视角:使用目标的伤害列表 if (battleHurtParam.hurter != null && battleHurtParam.hurter.damageList != null) return battleHurtParam.hurter.damageList; return new List(); } } public BattleObject hurtObj { get { // 如果是施法者视角,返回施法者作为受伤对象 if (isCasterView) return battleHurtParam.caster?.casterObj; // 否则返回目标 return battleHurtParam.hurter?.hurtObj; } } public BattleObject casterObj { get { return battleHurtParam.caster?.casterObj; } } public HB427_tagSCUseSkill.tagSCUseSkillHurt hurt { get { return battleHurtParam.hurt; } } public SkillConfig skillConfig { get { return battleHurtParam.skillConfig; } } public bool isBlocked = false; public bool isImmune = false; public bool isLastHit = false; public bool isFirstHit = false; public List targetDamageList = new List(); public List casterDamageList = new List(); public uint m_rawAttackType; #region Initialization public BattleDmgInfo(string battleFieldGuid, BattleHurtParam battleHurtParam, bool isCasterView = false) { this.battleFieldGuid = battleFieldGuid; this.battleHurtParam = battleHurtParam; this.isCasterView = isCasterView; this.isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillConfig.DamageDivide.Length - 1; this.isFirstHit = battleHurtParam.hitIndex == 0; m_rawAttackType = hurt == null ? 0 : hurt.AttackTypes; HandleDamageType(); HandleAttackTypeAndDamage(); } #endregion #region Damage Type Processing private void HandleDamageType() { if (hurt == null) return; uint originalAttackTypes = hurt.AttackTypes; int convertedAttackTypes = 0; // 遍历服务器发来的所有伤害类型标记 foreach (ServerDamageType serverDamageType in System.Enum.GetValues(typeof(ServerDamageType))) { int serverValue = (int)serverDamageType; // 检查服务器类型是否存在 if ((originalAttackTypes & serverValue) != serverValue) continue; // 转换映射 switch (serverDamageType) { case ServerDamageType.Damage: convertedAttackTypes |= (int)DamageType.Damage; break; case ServerDamageType.Recovery: convertedAttackTypes |= (int)DamageType.Recovery; break; case ServerDamageType.Immune: convertedAttackTypes |= (int)DamageType.Immune; break; case ServerDamageType.Block: convertedAttackTypes |= (int)DamageType.Block; break; case ServerDamageType.Realdamage: convertedAttackTypes |= (int)DamageType.Realdamage; break; case ServerDamageType.Crit: convertedAttackTypes |= (int)DamageType.Crit; break; case ServerDamageType.Stunned: convertedAttackTypes |= (int)DamageType.Stunned; break; case ServerDamageType.Dodge: convertedAttackTypes |= (int)DamageType.Dodge; break; case ServerDamageType.DamageReverse: convertedAttackTypes |= (int)DamageType.Damage; break; case ServerDamageType.SuckHpReverse: convertedAttackTypes |= (int)DamageType.Damage; break; case ServerDamageType.SelfHarm: convertedAttackTypes |= (int)DamageType.Damage; break; default: Debug.LogError($"[BattleDmgInfo] 未知的服务器伤害类型: {serverDamageType}({serverValue})"); break; } } // DOT技能特殊处理(SkillType == 3 或 4) if (skillConfig != null && (skillConfig.SkillType == 3 || skillConfig.SkillType == 4)) { // 如果是伤害类型,替换为流血类型 if ((convertedAttackTypes & (int)DamageType.Damage) != 0) { // 流血标记 convertedAttackTypes = (int)DamageType.Bloody; } // 治疗类型保持不变 } hurt.AttackTypes = (uint)convertedAttackTypes; } #endregion #region Damage List Generation // HandleAttackTypeAndDamage 中只生成对应视角的飘字列表 private void HandleAttackTypeAndDamage() { isBlocked = HaveBlockDamage(); isImmune = IsImmune(); int rawAttackType = hurt == null ? 0 : (int)hurt.AttackTypes; if (isImmune) { targetDamageList.Add(new BattleDmg { damage = 0, attackType = (int)DamageType.Immune }); return; } int maxCount = CalculateMaxDamageSegmentCount(); for (int i = 0; i < maxCount; i++) { if (isCasterView) { // 施法者视角:分别处理吸血和反伤,添加到targetDamageList用于飘字 // 注意:吸血和反伤是独立的飘字 ProcessSuckHpDamage(i); ProcessReflectDamage(i); } else { // 目标视角:只处理主伤害(吸血/反伤由施法者视角处理,避免重复) ProcessMainDamage(i, rawAttackType); } } } /// /// 计算最大伤害段数 /// private int CalculateMaxDamageSegmentCount() { int maxCount = 0; // 目标受伤的伤害段数 if (battleHurtParam.hurter != null && battleHurtParam.hurter.damageList != null) maxCount = Mathf.Max(maxCount, battleHurtParam.hurter.damageList.Count); // 施法者的吸血和反伤段数 if (battleHurtParam.caster != null) { if (battleHurtParam.caster.suckHpList != null) maxCount = Mathf.Max(maxCount, battleHurtParam.caster.suckHpList.Count); if (battleHurtParam.caster.reflectHpList != null) maxCount = Mathf.Max(maxCount, battleHurtParam.caster.reflectHpList.Count); } return maxCount; } /// /// 处理反伤伤害 /// private void ProcessReflectDamage(int segmentIndex) { if (battleHurtParam.caster == null || battleHurtParam.caster.reflectHpList == null) return; if (segmentIndex >= battleHurtParam.caster.reflectHpList.Count) return; long reflectHp = battleHurtParam.caster.reflectHpList[segmentIndex]; if (reflectHp > 0) { if (isCasterView) { // 施法者视角:反伤显示在自己身上(targetDamageList) targetDamageList.Add(new BattleDmg { damage = reflectHp, attackType = (int)DamageType.Reflect }); } else { // 目标视角:反伤显示在施法者身上(casterDamageList) casterDamageList.Add(new BattleDmg { damage = reflectHp, attackType = (int)DamageType.Reflect }); } } } /// /// 处理吸血伤害 /// private void ProcessSuckHpDamage(int segmentIndex) { if (battleHurtParam.caster == null || battleHurtParam.caster.suckHpList == null) return; if (segmentIndex >= battleHurtParam.caster.suckHpList.Count) return; long suckHp = battleHurtParam.caster.suckHpList[segmentIndex]; if (suckHp > 0) { if (isCasterView) { // 施法者视角:吸血显示在自己身上(targetDamageList) targetDamageList.Add(new BattleDmg { damage = suckHp, attackType = (int)DamageType.SuckHP }); } else { // 目标视角:吸血显示在施法者身上(casterDamageList) casterDamageList.Add(new BattleDmg { damage = suckHp, attackType = (int)DamageType.SuckHP }); } } } /// /// 处理主要伤害 /// private void ProcessMainDamage(int segmentIndex, int rawAttackType) { // 只处理目标受伤的主要伤害 if (battleHurtParam.hurter == null || battleHurtParam.hurter.damageList == null) return; if (segmentIndex >= battleHurtParam.hurter.damageList.Count) return; long actualDamage = battleHurtParam.hurter.damageList[segmentIndex]; if (isBlocked) { ProcessBlockedDamage(actualDamage, rawAttackType); } else { ProcessNormalDamage(actualDamage, rawAttackType); } } /// /// 处理被格挡的伤害 /// private void ProcessBlockedDamage(long actualDamage, int rawAttackType) { float blockRatio = GeneralDefine.blockRatio; int attackType = rawAttackType & (~(int)DamageType.Block); // 添加格挡伤害显示 long totalDamage = (long)(actualDamage / (1 - blockRatio)); long blockDmg = totalDamage - actualDamage; targetDamageList.Add(new BattleDmg { damage = blockDmg, attackType = (int)DamageType.Block }); // 添加实际伤害显示 if (IsRealdamage()) { AddRealdamageToList(actualDamage); } else { AddNormalDamageToList(actualDamage, attackType); } } /// /// 处理正常伤害(未被格挡) /// private void ProcessNormalDamage(long actualDamage, int rawAttackType) { if (IsRealdamage()) { AddRealdamageToList(actualDamage); } else { AddNormalDamageToList(actualDamage, rawAttackType); } } /// /// 添加真实伤害到列表 /// private void AddRealdamageToList(long damage) { int showAttackType = (int)DamageType.Realdamage + (IsCrit() ? (int)DamageType.Crit : 0); targetDamageList.Add(new BattleDmg { damage = damage, attackType = showAttackType }); } /// /// 添加普通伤害/治疗到列表 /// private void AddNormalDamageToList(long damage, int attackType) { attackType = ValidateAndFixAttackType(attackType); targetDamageList.Add(new BattleDmg { damage = damage, attackType = attackType }); } /// /// 验证并修复攻击类型 /// private int ValidateAndFixAttackType(int attackType) { if (IsType(DamageType.Stunned)) { // 特殊处理击晕类型 // 去掉击晕类型 attackType &= ~(int)DamageType.Stunned; } if (DamageNumConfig.Get(attackType) != null) return attackType; UnityEngine.Debug.LogError($"转换伤害类型错误或者未实现,强制转换为普通伤害/治疗, attackType: {attackType} rawAttackType: {m_rawAttackType}"); if ((attackType & (int)DamageType.Damage) != 0) return (int)DamageType.Damage; if ((attackType & (int)DamageType.Recovery) != 0) return (int)DamageType.Recovery; UnityEngine.Debug.LogError($"强制转换失败,该类型不是治疗也不是伤害 {attackType}"); return attackType; } #endregion #region Type Checking public bool IsType(DamageType damageType) { return hurt != null && (hurt.AttackTypes & (int)damageType) == (int)damageType; } public bool IsCrit() { return IsType(DamageType.Crit); } public bool HaveBlockDamage() { return IsType(DamageType.Block); } public bool IsImmune() { return IsType(DamageType.Immune); } public bool IsRealdamage() { return skillConfig.HurtType / 10 == 1; } public bool IsDamage() { return IsType(DamageType.Damage) || IsRealdamage() || IsType((DamageType)11) || IsType((DamageType)12); } #endregion } public class BattleHurtObj { public BattleObject hurtObj; public List damageList; public long fromHp; public long toHp; public long maxHp { get { return hurtObj != null ? hurtObj.teamHero.maxHp : 0; } } public long fromShieldValue; public long toShieldValue; public long totalDamage { get { long total = 0; if (damageList != null) { foreach (var dmg in damageList) { total += dmg; } } return total; } } } public class BattleCastObj { public BattleObject casterObj; public List suckHpList; public List reflectHpList; public long fromHp; public long toHp; public long maxHp { get { return casterObj != null ? casterObj.teamHero.maxHp : 0; } } public long fromShieldValue; public long toShieldValue; } public class BattleHurtParam { public BattleCastObj caster; public BattleHurtObj hurter; public BattleDrops battleDrops; public HB427_tagSCUseSkill.tagSCUseSkillHurt hurt; public HB427_tagSCUseSkill hB427_TagSCUseSkill; public int hitIndex; public BattleDeadPack deadPack; public SkillConfig skillConfig; }