fix(Core/Spells): remove one immunity entry per removal, not every entry of that spell (#27786)

Co-authored-by: Claude Opus 5 <[email protected]>
This commit is contained in:
Crow
2026-09-25 18:41:12 -03:00
committed by GitHub
co-authored by Claude Opus 5
parent 03f986f2f6
commit 081e3b1ad6
2 changed files with 18 additions and 25 deletions
+18 -14
View File
@@ -10204,29 +10204,33 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
return uint32(std::max(tmpDamage, 0.0f));
}
class spellIdImmunityPredicate
{
public:
spellIdImmunityPredicate(uint32 type) : _type(type) {}
bool operator()(SpellImmune const& spellImmune) { return spellImmune.spellId == 0 && spellImmune.type == _type; }
private:
uint32 _type;
};
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType /*blockType*/)
{
if (apply)
{
// Immunities with spellId 0 are applied by scripts and are meant to exist only once per type.
if (!spellId)
{
auto bounds = m_spellImmune[op].equal_range(type);
for (auto itr = bounds.first; itr != bounds.second; ++itr)
if (!itr->second)
return;
}
m_spellImmune[op].emplace(type, spellId);
}
else
{
// Remove a single entry: the same spell can be applied by several casters at once (e.g. the four
// Magic Barrier channels on Lady Vashj), and each removal must drop only the application it belongs to.
auto bounds = m_spellImmune[op].equal_range(type);
for (auto itr = bounds.first; itr != bounds.second;)
for (auto itr = bounds.first; itr != bounds.second; ++itr)
{
if (itr->second == spellId)
itr = m_spellImmune[op].erase(itr);
else
++itr;
{
m_spellImmune[op].erase(itr);
break;
}
}
}
}
-11
View File
@@ -178,17 +178,6 @@ public:
}
};
struct SpellImmune
{
SpellImmune() : spellId(0), type(IMMUNITY_EFFECT), blockType(SPELL_BLOCK_TYPE_ALL) { }
uint32 spellId;
uint32 type;
uint32 blockType;
};
typedef std::vector<SpellImmune> SpellImmuneList;
// AzerothCore note: TC keeps SpellCastTargets in SpellDefines.h, so its
// CastSpellTargetArg can hold an Optional<SpellCastTargets> by value.
// In AC, SpellCastTargets lives in Spell.h and depends on WorldLocation,