fix(Core/Spell): Impelement SPELL_ATTR7_NO_ATTACK_DODGE & SPELL_ATTR7_NO_ATTACK_PARRY & SPELL_ATTR7_NO_ATTACK_MISS (#7099)

cherry-pick commit (bd6de8eb61)

Co-Authored-By: Ovah <18347559+Ovahlord@users.noreply.github.com>
Co-Authored-By: Gildor <521036+Jildor@users.noreply.github.com>
This commit is contained in:
Kitzunu
2021-08-01 22:03:45 +02:00
committed by GitHub
parent 7f4c556148
commit 80ff915f24
2 changed files with 39 additions and 28 deletions

View File

@@ -2678,23 +2678,23 @@ int32 Unit::GetMechanicResistChance(const SpellInfo* spell)
}
// Melee based spells hit result calculations
SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
{
// Spells with SPELL_ATTR3_ALWAYS_HIT will additionally fully ignore
// resist and deflect chances
if (spell->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
if (spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
return SPELL_MISS_NONE;
WeaponAttackType attType = BASE_ATTACK;
// Check damage class instead of attack type to correctly handle judgements
// - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
attType = RANGED_ATTACK;
int32 attackerWeaponSkill;
// skill value for these spells (for example judgements) is 5* level
if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spell->IsRangedWeaponSpell())
if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spellInfo->IsRangedWeaponSpell())
attackerWeaponSkill = getLevel() * 5;
// bonus from skills is 0.04% per skill Diff
else
@@ -2704,22 +2704,22 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
uint32 roll = urand (0, 10000);
uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spell->Id) * 100.0f);
uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spellInfo->Id) * 100.0f);
// Roll miss
uint32 tmp = missChance;
if (roll < tmp)
return SPELL_MISS_MISS;
bool canDodge = true;
bool canParry = true;
bool canBlock = spell->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED) && !spell->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
bool canBlock = spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED) && !spellInfo->HasAttribute(SPELL_ATTR0_CU_DIRECT_DAMAGE);
// Same spells cannot be parry/dodge
if (spell->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE))
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE))
return SPELL_MISS_NONE;
// Chance resist mechanic
int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
tmp += resist_chance;
if (roll < tmp)
return SPELL_MISS_RESIST;
@@ -2742,7 +2742,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
// Check for attack from behind
// xinef: if from behind or spell requires cast from behind
if (!victim->HasInArc(M_PI, this) || spell->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
if (!victim->HasInArc(M_PI, this) || spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET))
{
if (!victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION))
{
@@ -2772,7 +2772,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
AuraEffectList const& ignore = GetAuraEffectsByType(SPELL_AURA_IGNORE_COMBAT_RESULT);
for (AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
{
if (!(*i)->IsAffectedOnSpell(spell))
if (!(*i)->IsAffectedOnSpell(spellInfo))
continue;
switch ((*i)->GetMiscValue())
{
@@ -2848,7 +2848,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell)
return SPELL_MISS_NONE;
}
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo)
{
// Can`t miss on dead target (on skinning for example)
if (!victim->IsAlive() && victim->GetTypeId() != TYPEID_PLAYER)
@@ -2861,15 +2861,20 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
// Spells with SPELL_ATTR3_ALWAYS_HIT will additionally fully ignore
// resist and deflect chances
// xinef: skip all calculations, proof: Toxic Tolerance quest
if (spell->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
if (spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
return SPELL_MISS_NONE;
SpellSchoolMask schoolMask = spell->GetSchoolMask();
if (spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
{
return SPELL_MISS_NONE;
}
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
// PvP - PvE spell misschances per leveldif > 2
int32 lchance = victim->GetTypeId() == TYPEID_PLAYER ? 7 : 11;
int32 thisLevel = getLevelForTarget(victim);
if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsTrigger())
thisLevel = std::max<int32>(thisLevel, spell->SpellLevel);
thisLevel = std::max<int32>(thisLevel, spellInfo->SpellLevel);
int32 leveldif = int32(victim->getLevelForTarget(this)) - thisLevel;
// Base hit chance from attacker and victim levels
@@ -2881,7 +2886,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
// Spellmod from SPELLMOD_RESIST_MISS_CHANCE
if (Player* modOwner = GetSpellModOwner())
modOwner->ApplySpellMod(spell->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_MISS_CHANCE, modHitChance);
// Increase from attacker SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT auras
modHitChance += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT, schoolMask);
@@ -2893,7 +2898,7 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
// Chance hit from victim SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE auras
modHitChance += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE, schoolMask);
// Reduce spell hit chance for Area of effect spells from victim SPELL_AURA_MOD_AOE_AVOIDANCE aura
if (spell->IsAffectingArea())
if (spellInfo->IsAffectingArea())
modHitChance -= victim->GetTotalAuraModifier(SPELL_AURA_MOD_AOE_AVOIDANCE);
// Decrease hit chance from victim rating bonus
@@ -2925,17 +2930,17 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
return SPELL_MISS_MISS;
// Chance resist mechanic (select max value from every mechanic spell effect)
int32 resist_chance = victim->GetMechanicResistChance(spell) * 100;
int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
tmp += resist_chance;
// Chance resist debuff
if (!spell->IsPositive() && !spell->HasAttribute(SPELL_ATTR4_NO_CAST_LOG))
if (!spellInfo->IsPositive() && !spellInfo->HasAttribute(SPELL_ATTR4_NO_CAST_LOG))
{
bool bNegativeAura = true;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
// Xinef: Check if effect exists!
if (spell->Effects[i].IsEffect() && spell->Effects[i].ApplyAuraName == 0)
if (spellInfo->Effects[i].IsEffect() && spellInfo->Effects[i].ApplyAuraName == 0)
{
bNegativeAura = false;
break;
@@ -2944,13 +2949,13 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell)
if (bNegativeAura)
{
tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spell->Dispel)) * 100;
tmp += victim->GetMaxPositiveAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100;
tmp += victim->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(spellInfo->Dispel)) * 100;
}
// Players resistance for binary spells
if (spell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spell->GetSchoolMask() & (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_MASK_HOLY)) == 0)
tmp += int32(Unit::GetEffectiveResistChance(this, spell->GetSchoolMask(), victim, spell) * 10000.0f); // 100 for spell calculations, and 100 for return value percentage
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL) && (spellInfo->GetSchoolMask() & (SPELL_SCHOOL_MASK_NORMAL | SPELL_SCHOOL_MASK_HOLY)) == 0)
tmp += int32(Unit::GetEffectiveResistChance(this, spellInfo->GetSchoolMask(), victim, spellInfo) * 10000.0f); // 100 for spell calculations, and 100 for return value percentage
}
// Roll chance
@@ -18199,6 +18204,12 @@ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool
// Crit or block - determined on damage calculation phase! (and can be both in some time)
float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
{
SpellInfo const* spellInfo = spellId ? sSpellMgr->GetSpellInfo(spellId) : nullptr;
if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
{
return 0.0f;
}
//calculate miss chance
float missChance = victim->GetUnitMissChance(attType);