mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 10:00:28 +00:00
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:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user