Skip to content

Commit

Permalink
[11623] Implement ClassFamilyMask as wrapper for uint64+uint32 spell …
Browse files Browse the repository at this point in the history
…family masks

Inspired by patch suggested by darkstalker

Also
* Remove existed enums for family masks as contra-productive for developement.
* Drop one from horrible hack checks in SpellMgr::IsNoStackSpellDueToSpell
  (spells for any fimilies with exactly 0x800 mask) I fail find useful cases
  for current spell data with this check. All cases expected work correct without it.
  If will some problems detected with this please report for fix in less strange way.
  • Loading branch information
VladimirMangos committed Jun 11, 2011
1 parent f33c298 commit 3248952
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 127 deletions.
59 changes: 51 additions & 8 deletions src/game/DBCStructure.h
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,42 @@ struct SoundEntriesEntry
// 29 m_soundEntriesAdvancedID
};


struct ClassFamilyMask
{
uint64 Flags;
uint32 Flags2;

ClassFamilyMask() : Flags(0), Flags2(0) {}
explicit ClassFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) : Flags(familyFlags), Flags2(familyFlags2) {}

bool Empty() const { return Flags == 0 && Flags2 == 0; }
bool operator! () const { return Empty(); }
operator void const* () const { return Empty() ? NULL : this; }// for allow normal use in if(mask)

bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const
{
return (Flags & familyFlags) || (Flags2 & familyFlags2);
}

bool IsFitToFamilyMask(ClassFamilyMask const& mask) const
{
return (Flags & mask.Flags) || (Flags2 & mask.Flags2);
}

uint64 operator& (uint64 mask) const // possible will removed at finish convertion code use IsFitToFamilyMask
{
return Flags & mask;
}

ClassFamilyMask& operator|= (ClassFamilyMask const& mask)
{
Flags |= mask.Flags;
Flags2 |= mask.Flags2;
return *this;
}
};

#define MAX_SPELL_REAGENTS 8
#define MAX_SPELL_TOTEMS 2
#define MAX_SPELL_TOTEM_CATEGORIES 2
Expand Down Expand Up @@ -1579,9 +1615,7 @@ struct SpellEntry
int32 EffectMiscValueB[MAX_EFFECT_INDEX]; // 113-115 m_effectMiscValueB
uint32 EffectTriggerSpell[MAX_EFFECT_INDEX]; // 116-118 m_effectTriggerSpell
float EffectPointsPerComboPoint[MAX_EFFECT_INDEX]; // 119-121 m_effectPointsPerCombo
uint32 EffectSpellClassMaskA[3]; // 122-124 m_effectSpellClassMaskA, effect 0
uint32 EffectSpellClassMaskB[3]; // 125-127 m_effectSpellClassMaskB, effect 1
uint32 EffectSpellClassMaskC[3]; // 128-130 m_effectSpellClassMaskC, effect 2
ClassFamilyMask EffectSpellClassMask[MAX_EFFECT_INDEX]; // 122-130 m_effectSpellClassMaskA/B/C, effect 0/1/2
uint32 SpellVisual[2]; // 131-132 m_spellVisualID
uint32 SpellIconID; // 133 m_spellIconID
uint32 activeIconID; // 134 m_activeIconID
Expand All @@ -1599,8 +1633,7 @@ struct SpellEntry
uint32 StartRecoveryTime; // 206 m_startRecoveryTime
uint32 MaxTargetLevel; // 207 m_maxTargetLevel
uint32 SpellFamilyName; // 208 m_spellClassSet
uint64 SpellFamilyFlags; // 209-210 m_spellClassMask NOTE: size is 12 bytes!!!
uint32 SpellFamilyFlags2; // 211 addition to m_spellClassMask
ClassFamilyMask SpellFamilyFlags; // 209-211 m_spellClassMask NOTE: size is 12 bytes!!!
uint32 MaxAffectedTargets; // 212 m_maxTargets
uint32 DmgClass; // 213 m_defenseType
uint32 PreventionType; // 214 m_preventionType
Expand All @@ -1621,21 +1654,31 @@ struct SpellEntry

// helpers
int32 CalculateSimpleValue(SpellEffectIndex eff) const { return EffectBasePoints[eff] + int32(1); }
uint32 const* GetEffectSpellClassMask(SpellEffectIndex effect) const
ClassFamilyMask const& GetEffectSpellClassMask(SpellEffectIndex effect) const
{
return EffectSpellClassMaskA + effect * 3;
return EffectSpellClassMask[effect];
}

bool IsFitToFamilyMask(uint64 familyFlags, uint32 familyFlags2 = 0) const
{
return (SpellFamilyFlags & familyFlags) || (SpellFamilyFlags2 & familyFlags2);
return SpellFamilyFlags.IsFitToFamilyMask(familyFlags, familyFlags2);
}

bool IsFitToFamily(SpellFamily family, uint64 familyFlags, uint32 familyFlags2 = 0) const
{
return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(familyFlags, familyFlags2);
}

bool IsFitToFamilyMask(ClassFamilyMask const& mask) const
{
return SpellFamilyFlags.IsFitToFamilyMask(mask);
}

bool IsFitToFamily(SpellFamily family, ClassFamilyMask const& mask) const
{
return SpellFamily(SpellFamilyName) == family && IsFitToFamilyMask(mask);
}

private:
// prevent creating custom entries (copy data from original in fact)
SpellEntry(SpellEntry const&); // DON'T must have implementation
Expand Down
23 changes: 7 additions & 16 deletions src/game/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,29 +274,21 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)

SpellModifier::SpellModifier( SpellModOp _op, SpellModType _type, int32 _value, SpellEntry const* spellEntry, SpellEffectIndex eff, int16 _charges /*= 0*/ ) : op(_op), type(_type), charges(_charges), value(_value), spellId(spellEntry->Id), lastAffected(NULL)
{
uint32 const* ptr = spellEntry->GetEffectSpellClassMask(eff);
mask = uint64(ptr[0]) | (uint64(ptr[1]) << 32);
mask2= ptr[2];
mask = spellEntry->GetEffectSpellClassMask(eff);
}

SpellModifier::SpellModifier( SpellModOp _op, SpellModType _type, int32 _value, Aura const* aura, int16 _charges /*= 0*/ ) : op(_op), type(_type), charges(_charges), value(_value), spellId(aura->GetId()), lastAffected(NULL)
{
uint32 const* ptr = aura->getAuraSpellClassMask();
mask = uint64(ptr[0]) | (uint64(ptr[1]) << 32);
mask2= ptr[2];
mask = aura->GetAuraSpellClassMask();
}

bool SpellModifier::isAffectedOnSpell( SpellEntry const *spell ) const
{
SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId);
// False if affect_spell == NULL or spellFamily not equal
if (!affect_spell || affect_spell->SpellFamilyName != spell->SpellFamilyName)
if (!affect_spell)
return false;
if (mask & spell->SpellFamilyFlags)
return true;
if (mask2 & spell->SpellFamilyFlags2)
return true;
return false;
return affect_spell->IsFitToFamily(SpellFamily(spell->SpellFamilyName), spell->SpellFamilyFlags);
}

//== TradeData =================================================
Expand Down Expand Up @@ -18564,12 +18556,12 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply)
else
_mask2= uint32(1) << (eff - 64);

if ( mod->mask & _mask || mod->mask2 & _mask2)
if (mod->mask.IsFitToFamilyMask(_mask, _mask2))
{
int32 val = 0;
for (SpellModList::const_iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr)
{
if ((*itr)->type == mod->type && ((*itr)->mask & _mask || (*itr)->mask2 & _mask2))
if ((*itr)->type == mod->type && ((*itr)->mask.IsFitToFamilyMask(_mask, _mask2)))
val += (*itr)->value;
}
val += apply ? mod->value : -(mod->value);
Expand Down Expand Up @@ -20832,8 +20824,7 @@ bool Player::CanNoReagentCast(SpellEntry const* spellInfo) const
// Check no reagent use mask
uint64 noReagentMask_0_1 = GetUInt64Value(PLAYER_NO_REAGENT_COST_1);
uint32 noReagentMask_2 = GetUInt32Value(PLAYER_NO_REAGENT_COST_1+2);
if (spellInfo->SpellFamilyFlags & noReagentMask_0_1 ||
spellInfo->SpellFamilyFlags2 & noReagentMask_2)
if (spellInfo->IsFitToFamilyMask(noReagentMask_0_1, noReagentMask_2))
return true;

return false;
Expand Down
9 changes: 6 additions & 3 deletions src/game/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ struct SpellModifier
SpellModifier() : charges(0), lastAffected(NULL) {}

SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, uint32 _spellId, uint64 _mask, uint32 _mask2 = 0, int16 _charges = 0)
: op(_op), type(_type), charges(_charges), value(_value), mask(_mask), mask2(_mask2), spellId(_spellId), lastAffected(NULL)
: op(_op), type(_type), charges(_charges), value(_value), mask(_mask, _mask2), spellId(_spellId), lastAffected(NULL)
{}

SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, uint32 _spellId, ClassFamilyMask _mask, int16 _charges = 0)
: op(_op), type(_type), charges(_charges), value(_value), mask(_mask), spellId(_spellId), lastAffected(NULL)
{}

SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, SpellEntry const* spellEntry, SpellEffectIndex eff, int16 _charges = 0);
Expand All @@ -133,8 +137,7 @@ struct SpellModifier
SpellModType type : 8;
int16 charges : 16;
int32 value;
uint64 mask;
uint32 mask2;
ClassFamilyMask mask;
uint32 spellId;
Spell const* lastAffected;
};
Expand Down
4 changes: 2 additions & 2 deletions src/game/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4787,8 +4787,8 @@ SpellCastResult Spell::CheckCast(bool strict)
// Exclusion for Pounce: Facing Limitation was removed in 2.0.1, but it still uses the same, old Ex-Flags
// Exclusion for Mutilate:Facing Limitation was removed in 2.0.1 and 3.0.3, but they still use the same, old Ex-Flags
// Exclusion for Throw: Facing limitation was added in 3.2.x, but that shouldn't be
if ((m_spellInfo->SpellFamilyName != SPELLFAMILY_DRUID || (m_spellInfo->SpellFamilyFlags != UI64LIT(0x0000000000020000))) &&
(m_spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE || (m_spellInfo->SpellFamilyFlags != UI64LIT(0x0020000000000000))) &&
if (!m_spellInfo->IsFitToFamily(SPELLFAMILY_DRUID, UI64LIT(0x0000000000020000)) &&
!m_spellInfo->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x0020000000000000)) &&
m_spellInfo->Id != 2764)
{
SendInterrupted(2);
Expand Down
57 changes: 17 additions & 40 deletions src/game/SpellAuras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,25 +852,16 @@ void Aura::ApplyModifier(bool apply, bool Real)

bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
{
// Check family name
if (spell->SpellFamilyName != GetSpellProto()->SpellFamilyName)
return false;
// Check EffectClassMask
uint32 const *ptr = getAuraSpellClassMask();
if (((uint64*)ptr)[0] & spell->SpellFamilyFlags)
return true;
if (ptr[2] & spell->SpellFamilyFlags2)
return true;
return false;
return spell->IsFitToFamily(SpellFamily(GetSpellProto()->SpellFamilyName), GetAuraSpellClassMask());
}

bool Aura::CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const
{
// Check EffectClassMask
uint32 const *ptr = getAuraSpellClassMask();
ClassFamilyMask const& mask = GetAuraSpellClassMask();

// if no class mask defined, or spell_proc_event has SpellFamilyName=0 - allow proc
if (!useClassMask || (!((uint64*)ptr)[0] && !ptr[2]))
if (!useClassMask || !mask)
{
if (!(EventProcEx & PROC_EX_EX_TRIGGER_ALWAYS))
{
Expand All @@ -896,14 +887,8 @@ bool Aura::CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procE
{
// SpellFamilyName check is performed in SpellMgr::IsSpellProcEventCanTriggeredBy and it is done once for whole holder
// note: SpellFamilyName is not checked if no spell_proc_event is defined

if (((uint64*)ptr)[0] & spell->SpellFamilyFlags)
return true;

if (ptr[2] & spell->SpellFamilyFlags2)
return true;
return mask.IsFitToFamilyMask(spell->SpellFamilyFlags);
}
return false;
}

void Aura::ReapplyAffectedPassiveAuras( Unit* target, bool owner_mode )
Expand Down Expand Up @@ -1042,14 +1027,14 @@ void Aura::HandleAddModifier(bool apply, bool Real)
// Everlasting Affliction, overwrite wrong data, if will need more better restore support of spell_affect table
if (spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellIconID == 3169)
{
m_spellmod->mask = UI64LIT(0x0000010000000002); // Corruption and Unstable Affliction
m_spellmod->mask2 = 0x00000000;
// Corruption and Unstable Affliction
m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000010000000002));
}
// Improved Flametongue Weapon, overwrite wrong data, maybe time re-add table
else if (spellProto->Id == 37212)
{
m_spellmod->mask = UI64LIT(0x0000000000200000); // Flametongue Weapon (Passive)
m_spellmod->mask2 = 0x00000000;
// Flametongue Weapon (Passive)
m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000000000200000));
}
}

Expand Down Expand Up @@ -6358,19 +6343,13 @@ void Aura::HandleNoReagentUseAura(bool /*Apply*/, bool Real)
if(target->GetTypeId() != TYPEID_PLAYER)
return;

uint32 mask[3] = {0, 0, 0};
ClassFamilyMask mask;
Unit::AuraList const& noReagent = target->GetAurasByType(SPELL_AURA_NO_REAGENT_USE);
for(Unit::AuraList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i)
{
uint32 const *ptr = (*i)->getAuraSpellClassMask();
mask[0] |= ptr[0];
mask[1] |= ptr[1];
mask[2] |= ptr[2];
}
for(Unit::AuraList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i)
mask |= (*i)->GetAuraSpellClassMask();

target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+0, mask[0]);
target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]);
target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask[2]);
target->SetUInt64Value(PLAYER_NO_REAGENT_COST_1+0, mask.Flags);
target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask.Flags2);
}

/*********************************************************/
Expand Down Expand Up @@ -8626,8 +8605,7 @@ void SpellAuraHolder::_RemoveSpellAuraHolder()
}

uint32 removeState = 0;
uint64 removeFamilyFlag = m_spellProto->SpellFamilyFlags;
uint32 removeFamilyFlag2 = m_spellProto->SpellFamilyFlags2;
ClassFamilyMask removeFamilyFlag = m_spellProto->SpellFamilyFlags;
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_PALADIN:
Expand All @@ -8638,8 +8616,7 @@ void SpellAuraHolder::_RemoveSpellAuraHolder()
// Conflagrate aura state on Immolate and Shadowflame,
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000004), 0x00000002))
{
removeFamilyFlag = UI64LIT(0x0000000000000004);
removeFamilyFlag2 = 0x00000002;
removeFamilyFlag = ClassFamilyMask(UI64LIT(0x0000000000000004), 0x00000002);
removeState = AURA_STATE_CONFLAGRATE;
}
break;
Expand All @@ -8648,7 +8625,7 @@ void SpellAuraHolder::_RemoveSpellAuraHolder()
removeState = AURA_STATE_FAERIE_FIRE; // Faerie Fire (druid versions)
else if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000050)))
{
removeFamilyFlag = 0x50;
removeFamilyFlag = ClassFamilyMask(UI64LIT(0x00000000000050));
removeState = AURA_STATE_SWIFTMEND; // Swiftmend aura state
}
break;
Expand All @@ -8673,7 +8650,7 @@ void SpellAuraHolder::_RemoveSpellAuraHolder()
for (Unit::SpellAuraHolderMap::const_iterator i = holders.begin(); i != holders.end(); ++i)
{
SpellEntry const *auraSpellInfo = (*i).second->GetSpellProto();
if (auraSpellInfo->IsFitToFamily(SpellFamily(m_spellProto->SpellFamilyName), removeFamilyFlag, removeFamilyFlag2))
if (auraSpellInfo->IsFitToFamily(SpellFamily(m_spellProto->SpellFamilyName), removeFamilyFlag))
{
found = true;
break;
Expand Down
2 changes: 1 addition & 1 deletion src/game/SpellAuras.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ class MANGOS_DLL_SPEC Aura
void TriggerSpell();
void TriggerSpellWithValue();

uint32 const *getAuraSpellClassMask() const { return m_spellAuraHolder->GetSpellProto()->GetEffectSpellClassMask(m_effIndex); }
ClassFamilyMask const& GetAuraSpellClassMask() const { return m_spellAuraHolder->GetSpellProto()->GetEffectSpellClassMask(m_effIndex); }
bool isAffectedOnSpell(SpellEntry const *spell) const;
bool CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const;

Expand Down
17 changes: 8 additions & 9 deletions src/game/SpellEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6061,7 +6061,7 @@ void Spell::EffectWeaponDmg(SpellEffectIndex eff_idx)
((Player*)m_caster)->AddComboPoints(unitTarget, 1);
}
// Mangle (Cat): CP
else if (m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==UI64LIT(0x0000040000000000)))
else if (m_spellInfo->IsFitToFamily(SPELLFAMILY_DRUID, UI64LIT(0x0000040000000000)))
{
if(m_caster->GetTypeId()==TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget, 1);
Expand Down Expand Up @@ -7494,8 +7494,8 @@ void Spell::EffectScriptEffect(SpellEffectIndex eff_idx)
continue;

// Search only Serpent Sting, Viper Sting, Scorpid Sting auras
uint64 familyFlag = holder->GetSpellProto()->SpellFamilyFlags;
if (!(familyFlag & UI64LIT(0x000000800000C000)))
ClassFamilyMask const& familyFlag = holder->GetSpellProto()->SpellFamilyFlags;
if (!familyFlag.IsFitToFamilyMask(UI64LIT(0x000000800000C000)))
continue;

// Refresh aura duration
Expand All @@ -7507,15 +7507,15 @@ void Spell::EffectScriptEffect(SpellEffectIndex eff_idx)
continue;

// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if ((familyFlag & UI64LIT(0x0000000000004000)))
if (familyFlag.IsFitToFamilyMask(UI64LIT(0x0000000000004000)))
{
// m_amount already include RAP bonus
basePoint = aura->GetModifier()->m_amount * aura->GetAuraMaxTicks() * 40 / 100;
spellId = 53353; // Chimera Shot - Serpent
}

// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
if ((familyFlag & UI64LIT(0x0000008000000000)))
if (familyFlag.IsFitToFamilyMask(UI64LIT(0x0000008000000000)))
{
uint32 target_max_mana = unitTarget->GetMaxPower(POWER_MANA);
if (!target_max_mana)
Expand All @@ -7538,7 +7538,7 @@ void Spell::EffectScriptEffect(SpellEffectIndex eff_idx)
}

// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
if (familyFlag & UI64LIT(0x0000000000008000))
if (familyFlag.IsFitToFamilyMask(UI64LIT(0x0000000000008000)))
spellId = 53359; // Chimera Shot - Scorpid
// ?? nothing say in spell desc (possibly need addition check)
//if ((familyFlag & UI64LIT(0x0000010000000000)) || // dot
Expand Down Expand Up @@ -7743,11 +7743,10 @@ void Spell::EffectSanctuary(SpellEffectIndex /*eff_idx*/)

unitTarget->CombatStop();
unitTarget->getHostileRefManager().deleteReferences(); // stop all fighting

// Vanish allows to remove all threat and cast regular stealth so other spells can be used
if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
{
if (m_spellInfo->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x0000000000000800)))
((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
}
}

void Spell::EffectAddComboPoints(SpellEffectIndex /*eff_idx*/)
Expand Down

5 comments on commit 3248952

@SeTM
Copy link

@SeTM SeTM commented on 3248952 Jun 12, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isAffectedOnSpell broken after that

@VladimirMangos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aura:isAffectedOnSpell or SpellModifer::isAffectedOnSpell ?

@VladimirMangos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, i found wrong code in SpellModifier::isAffectedOnSpell. Fix testing...

@VladimirMangos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be fixed in [11627]. Thank you for pointing.

@wolfiestyle
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm a good source of inspiration it seems ^^

Please sign in to comment.