From 01caaecf0f22b6a23c7aeebe7fe027772966403b Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sat, 30 Dec 2017 17:53:28 -0500 Subject: [PATCH] Core/Unit: damage immune improvements --- Source/Game/Chat/Commands/MiscCommands.cs | 20 +++++++------ Source/Game/Entities/Unit/Unit.Combat.cs | 31 +++++++++------------ Source/Game/Entities/Unit/Unit.Spells.cs | 5 ++++ Source/Game/Spells/Auras/AuraEffect.cs | 6 ++++ Source/Game/Spells/Spell.cs | 34 +++++++++++++++-------- Source/Game/Spells/SpellInfo.cs | 29 +++++++++++++++++++ 6 files changed, 87 insertions(+), 38 deletions(-) diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index 817fe1999..3b0157d3f 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -2039,12 +2039,14 @@ namespace Game.Chat string schoolStr = args.NextString(); + Player attacker = handler.GetSession().GetPlayer(); + // flat melee damage without resistence/etc reduction if (string.IsNullOrEmpty(schoolStr)) { - handler.GetSession().GetPlayer().DealDamage(target, damage_, null, DamageEffectType.Direct, SpellSchoolMask.Normal, null, false); - if (target != handler.GetSession().GetPlayer()) - handler.GetSession().GetPlayer().SendAttackStateUpdate(HitInfo.AffectsVictim, target, SpellSchoolMask.Normal, damage_, 0, 0, VictimState.Hit, 0); + attacker.DealDamage(target, damage_, null, DamageEffectType.Direct, SpellSchoolMask.Normal, null, false); + if (target != attacker) + attacker.SendAttackStateUpdate(HitInfo.AffectsVictim, target, SpellSchoolMask.Normal, damage_, 0, 0, VictimState.Hit, 0); return true; } @@ -2053,15 +2055,14 @@ namespace Game.Chat SpellSchoolMask schoolmask = (SpellSchoolMask)(1 << school); - if (handler.GetSession().GetPlayer().IsDamageReducedByArmor(schoolmask)) - damage_ = handler.GetSession().GetPlayer().CalcArmorReducedDamage(handler.GetPlayer(), target, damage_, null, WeaponAttackType.BaseAttack); + if (attacker.IsDamageReducedByArmor(schoolmask)) + damage_ = attacker.CalcArmorReducedDamage(handler.GetPlayer(), target, damage_, null, WeaponAttackType.BaseAttack); string spellStr = args.NextString(); // melee damage by specific school if (string.IsNullOrEmpty(spellStr)) { - Player attacker = handler.GetSession().GetPlayer(); DamageInfo dmgInfo = new DamageInfo(attacker, target, damage_, null, schoolmask, DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); attacker.CalcAbsorbResist(dmgInfo); @@ -2081,13 +2082,16 @@ namespace Game.Chat // non-melee damage // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint spellid = handler.extractSpellIdFromLink(args); + if (spellid == 0) + return false; + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid); if (spellInfo == null) return false; - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(handler.GetSession().GetPlayer(), target, spellid, spellInfo.GetSpellXSpellVisualId(handler.GetSession().GetPlayer()), spellInfo.SchoolMask); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(attacker, target, spellid, spellInfo.GetSpellXSpellVisualId(attacker), spellInfo.SchoolMask); damageInfo.damage = damage_; - handler.GetSession().GetPlayer().DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); + attacker.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); target.DealSpellDamage(damageInfo, true); target.SendSpellNonMeleeDamageLog(damageInfo); return true; diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 5ca2b2353..747ba657b 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -810,19 +810,20 @@ namespace Game.Entities var vDamageShieldsCopy = victim.GetAuraEffectsByType(AuraType.DamageShield); foreach (var dmgShield in vDamageShieldsCopy) { - SpellInfo i_spellProto = dmgShield.GetSpellInfo(); + SpellInfo spellInfo = dmgShield.GetSpellInfo(); + // Damage shield can be resisted... - var missInfo = victim.SpellHitResult(this, i_spellProto, false); - if (missInfo != 0) + var missInfo = victim.SpellHitResult(this, spellInfo, false); + if (missInfo != SpellMissInfo.None) { - victim.SendSpellMiss(this, i_spellProto.Id, missInfo); + victim.SendSpellMiss(this, spellInfo.Id, missInfo); continue; } // ...or immuned - if (IsImmunedToDamage(i_spellProto)) + if (IsImmunedToDamage(spellInfo)) { - victim.SendSpellDamageImmune(this, i_spellProto.Id, false); + victim.SendSpellDamageImmune(this, spellInfo.Id, false); continue; } @@ -830,11 +831,11 @@ namespace Game.Entities Unit caster = dmgShield.GetCaster(); if (caster) { - damage = caster.SpellDamageBonusDone(this, i_spellProto, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); - damage = SpellDamageBonusTaken(caster, i_spellProto, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); + damage = caster.SpellDamageBonusDone(this, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); + damage = SpellDamageBonusTaken(caster, spellInfo, damage, DamageEffectType.SpellDirect, dmgShield.GetSpellEffectInfo()); } - DamageInfo damageInfo1 = new DamageInfo(this, victim, damage, i_spellProto, i_spellProto.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); + DamageInfo damageInfo1 = new DamageInfo(this, victim, damage, spellInfo, spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); victim.CalcAbsorbResist(damageInfo1); damage = damageInfo1.GetDamage(); // No Unit.CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that @@ -843,13 +844,13 @@ namespace Game.Entities SpellDamageShield damageShield = new SpellDamageShield(); damageShield.Attacker = victim.GetGUID(); damageShield.Defender = GetGUID(); - damageShield.SpellID = i_spellProto.Id; + damageShield.SpellID = spellInfo.Id; damageShield.TotalDamage = damage; damageShield.OverKill = (uint)Math.Max(damage - GetHealth(), 0); - damageShield.SchoolMask = (uint)i_spellProto.SchoolMask; + damageShield.SchoolMask = (uint)spellInfo.SchoolMask; damageShield.LogAbsorbed = damageInfo1.GetAbsorb(); - victim.DealDamage(this, damage, null, DamageEffectType.SpellDirect, i_spellProto.GetSchoolMask(), i_spellProto, true); + victim.DealDamage(this, damage, null, DamageEffectType.SpellDirect, spellInfo.GetSchoolMask(), spellInfo, true); damageShield.LogData.Initialize(this); victim.SendCombatLogMessage(damageShield); @@ -858,12 +859,6 @@ namespace Game.Entities } public uint DealDamage(Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true) { - if (victim.IsImmunedToDamage(spellProto)) - { - SendSpellDamageImmune(victim, spellProto.Id, false); - return 0; - } - if (victim.IsAIEnabled) victim.GetAI().DamageTaken(this, ref damage); diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 472c16907..bce1fbf99 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -803,6 +803,11 @@ namespace Game.Entities if (victim.IsImmunedToSpell(spellInfo)) return SpellMissInfo.Immune; + // Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply + // returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit + if (spellInfo.HasOnlyDamageEffects() && victim.IsImmunedToDamage(spellInfo)) + return SpellMissInfo.Immune; + // All positive spells can`t miss // @todo client not show miss log for this spells - so need find info for this in dbc and use it! if (spellInfo.IsPositive() diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index d0e42a266..b608df7e5 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -5797,6 +5797,12 @@ namespace Game.Spells { Unit target = aurApp.GetTarget(); Unit triggerTarget = eventInfo.GetProcTarget(); + if (triggerTarget.HasUnitState(UnitState.Isolated) || triggerTarget.IsImmunedToDamage(GetSpellInfo())) + { + SendTickImmune(triggerTarget, target); + return; + } + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(target, triggerTarget, GetId(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().SchoolMask, GetBase().GetCastGUID()); int damage = (int)target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), (uint)GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo()); damage = (int)triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), (uint)damage, DamageEffectType.SpellDirect, GetSpellEffectInfo()); diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index e7e405b3d..32e88bfe4 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2001,12 +2001,29 @@ namespace Game.Spells // Fill base damage struct (unitTarget - is real spell target) SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellSchoolMask, m_castId); - // Add bonuses and fill damageInfo struct - caster.CalculateSpellDamageTaken(damageInfo, m_damage, m_spellInfo, m_attackType, target.crit); - caster.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); + // Check damage immunity + if (unitTarget.IsImmunedToDamage(m_spellInfo)) + { + hitMask = ProcFlagsHit.Immune; + m_damage = 0; + // no packet found in sniffs + } + else + { + // Add bonuses and fill damageInfo struct + caster.CalculateSpellDamageTaken(damageInfo, m_damage, m_spellInfo, m_attackType, target.crit); + caster.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); - hitMask |= Unit.createProcHitMask(damageInfo, missInfo); - procVictim |= ProcFlags.TakenDamage; + hitMask |= Unit.createProcHitMask(damageInfo, missInfo); + procVictim |= ProcFlags.TakenDamage; + + m_damage = (int)damageInfo.damage; + + caster.DealSpellDamage(damageInfo, true); + + // Send log damage message to client + caster.SendSpellNonMeleeDamageLog(damageInfo); + } // Do triggers for unit if (canEffectTrigger) @@ -2018,13 +2035,6 @@ namespace Game.Spells (m_spellInfo.DmgClass == SpellDmgClass.Melee || m_spellInfo.DmgClass == SpellDmgClass.Ranged)) caster.ToPlayer().CastItemCombatSpell(spellDamageInfo); } - - m_damage = (int)damageInfo.damage; - - caster.DealSpellDamage(damageInfo, true); - - // Send log damage message to client - caster.SendSpellNonMeleeDamageLog(damageInfo); } // Passive spell hits/misses or active spells only misses (only triggers) else diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 2c6961d46..e0a529381 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -311,6 +311,35 @@ namespace Game.Spells return false; } + public bool HasOnlyDamageEffects() + { + foreach (var pair in _effects) + { + foreach (SpellEffectInfo effect in pair.Value) + { + if (effect == null) + continue; + + switch (effect.Effect) + { + case SpellEffectName.WeaponDamage: + case SpellEffectName.WeaponDamageNoschool: + case SpellEffectName.NormalizedWeaponDmg: + case SpellEffectName.WeaponPercentDamage: + case SpellEffectName.SchoolDamage: + case SpellEffectName.EnvironmentalDamage: + case SpellEffectName.HealthLeech: + case SpellEffectName.DamageFromMaxHealthPCT: + continue; + default: + return false; + } + } + } + + return true; + } + public bool IsExplicitDiscovery() { SpellEffectInfo effect0 = GetEffect(Difficulty.None, 0);