diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ca684c310..f01a86566 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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(thisLevel, spell->SpellLevel); + thisLevel = std::max(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); diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 480729305..837b901bc 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -548,9 +548,9 @@ enum SpellAttr7 SPELL_ATTR7_NO_CLIENT_FAIL_WHILE_STUNNED_FLEEING_CONFUSED = 0x00100000, // TITLE Unknown attribute 20@Attr7 DESCRIPTION Invulnerability related? SPELL_ATTR7_RETAIN_COOLDOWN_THROUGH_LOAD = 0x00200000, // TITLE Unknown attribute 21@Attr7 SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT = 0x00400000, // TITLE Ignore cold weather flying restriction DESCRIPTION Set for loaner mounts, allows them to be used despite lacking required flight skill - SPELL_ATTR7_NO_ATTACK_DODGE = 0x00800000, // TITLE Unknown attribute 23@Attr7 DESCRIPTION Motivate, Mutilate, Shattering Throw - SPELL_ATTR7_NO_ATTACK_PARRY = 0x01000000, // TITLE Unknown attribute 24@Attr7 DESCRIPTION Motivate, Mutilate, Perform Speech, Shattering Throw - SPELL_ATTR7_NO_ATTACK_MISS = 0x02000000, // TITLE Unknown attribute 25@Attr7 + SPELL_ATTR7_NO_ATTACK_DODGE = 0x00800000, // TITLE Spell cannot be dodged 23@Attr7 DESCRIPTION Motivate, Mutilate, Shattering Throw + SPELL_ATTR7_NO_ATTACK_PARRY = 0x01000000, // TITLE Spell cannot be parried 24@Attr7 DESCRIPTION Motivate, Mutilate, Perform Speech, Shattering Throw + SPELL_ATTR7_NO_ATTACK_MISS = 0x02000000, // TITLE Spell cannot be missed 25@Attr7 SPELL_ATTR7_TREAT_AS_NPC_AOE = 0x04000000, // TITLE Unknown attribute 26@Attr7 SPELL_ATTR7_BYPASS_NO_RESSURECTION_AURA = 0x08000000, // TITLE Unknown attribute 27@Attr7 SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD = 0x10000000, // TITLE Consolidate in raid buff frame (client only)