aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells/Spell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r--src/server/game/Spells/Spell.cpp508
1 files changed, 292 insertions, 216 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 5ccd5ee6e21..f8f1dc773ff 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -2599,7 +2599,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
- if (m_spellInfo->Speed && (unit->IsImmunedToDamage(m_spellInfo) || unit->IsImmunedToSpell(m_spellInfo)))
+ if (m_spellInfo->Speed && unit->IsImmunedToSpell(m_spellInfo))
return SPELL_MISS_IMMUNE;
// disable effects to which unit is immune
@@ -3013,7 +3013,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe)
m_needComboPoints = false;
- SpellCastResult result = CheckCast(true);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult result = CheckCast(true, &param1, &param2);
// target is checked in too many locations and with different results to handle each of them
// handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
if (_triggeredCastFlags & TRIGGERED_IGNORE_TARGET_CHECK && result == SPELL_FAILED_BAD_TARGETS)
@@ -3038,7 +3039,10 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
}
- SendCastResult(result);
+ if (param1 || param2)
+ SendCastResult(result, &param1, &param2);
+ else
+ SendCastResult(result);
finish(false);
return;
@@ -3227,10 +3231,11 @@ void Spell::cast(bool skipCheck)
// skip check if done already (for instant cast spells for example)
if (!skipCheck)
{
- SpellCastResult castResult = CheckCast(false);
+ uint32 param1 = 0, param2 = 0;
+ SpellCastResult castResult = CheckCast(false, &param1, &param2);
if (castResult != SPELL_CAST_OK)
{
- SendCastResult(castResult);
+ SendCastResult(castResult, &param1, &param2);
SendInterrupted(0);
//restore spell mods
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -3782,7 +3787,7 @@ void Spell::finish(bool ok)
}
template<class T>
-inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32* misc, Player* caster)
+inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/, Player* caster)
{
packet.CastID = castId;
packet.SpellID = spellInfo->Id;
@@ -3791,109 +3796,182 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons
switch (result)
{
case SPELL_FAILED_NOT_READY:
- packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
+ if (*param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
break;
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
- packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
break;
- case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
- // hardcode areas limitation case
- switch (spellInfo->Id)
+ case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
{
- case 41617: // Cenarion Mana Salve
- case 41619: // Cenarion Healing Salve
- packet.FailedArg1 = 3905;
- break;
- case 41618: // Bottled Nethergon Energy
- case 41620: // Bottled Nethergon Vapor
- packet.FailedArg1 = 3842;
- break;
- case 45373: // Bloodberry Elixir
- packet.FailedArg1 = 4075;
- break;
- default: // default case (don't must be)
- packet.FailedArg1 = 0;
- break;
+ // hardcode areas limitation case
+ switch (spellInfo->Id)
+ {
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
+ packet.FailedArg1 = 3905;
+ break;
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
+ packet.FailedArg1 = 3842;
+ break;
+ case 45373: // Bloodberry Elixir
+ packet.FailedArg1 = 4075;
+ break;
+ default: // default case (don't must be)
+ packet.FailedArg1 = 0;
+ break;
+ }
}
break;
case SPELL_FAILED_TOTEMS:
- if (spellInfo->Totem[0])
- packet.FailedArg1 = spellInfo->Totem[0];
- if (spellInfo->Totem[1])
- packet.FailedArg2 = spellInfo->Totem[1];
+ if (param1)
+ {
+ packet.FailedArg1 = *param1;
+ if (param2)
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ if (spellInfo->Totem[0])
+ packet.FailedArg1 = spellInfo->Totem[0];
+ if (spellInfo->Totem[1])
+ packet.FailedArg2 = spellInfo->Totem[1];
+ }
break;
case SPELL_FAILED_TOTEM_CATEGORY:
- if (spellInfo->TotemCategory[0])
- packet.FailedArg1 = spellInfo->TotemCategory[0];
- if (spellInfo->TotemCategory[1])
- packet.FailedArg2 = spellInfo->TotemCategory[1];
+ if (param1)
+ {
+ packet.FailedArg1 = *param1;
+ if (param2)
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ if (spellInfo->TotemCategory[0])
+ packet.FailedArg1 = spellInfo->TotemCategory[0];
+ if (spellInfo->TotemCategory[1])
+ packet.FailedArg2 = spellInfo->TotemCategory[1];
+ }
break;
case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND:
case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND:
- packet.FailedArg1 = spellInfo->EquippedItemClass;
- packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = spellInfo->EquippedItemClass;
+ packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
+ }
break;
case SPELL_FAILED_TOO_MANY_OF_ITEM:
{
- uint32 item = 0;
- for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()))
- if (effect->ItemType)
- item = effect->ItemType;
- ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
- if (proto && proto->GetItemLimitCategory())
- packet.FailedArg1 = proto->GetItemLimitCategory();
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ {
+ uint32 item = 0;
+ for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()))
+ if (effect->ItemType)
+ item = effect->ItemType;
+ ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
+ if (proto && proto->GetItemLimitCategory())
+ packet.FailedArg1 = proto->GetItemLimitCategory();
+ }
break;
}
case SPELL_FAILED_PREVENTED_BY_MECHANIC:
- packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
break;
case SPELL_FAILED_NEED_EXOTIC_AMMO:
- packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
break;
case SPELL_FAILED_NEED_MORE_ITEMS:
- packet.FailedArg1 = 0; // Item id
- packet.FailedArg2 = 0; // Item count?
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = 0; // Item id
+ packet.FailedArg2 = 0; // Item count?
+ }
break;
case SPELL_FAILED_MIN_SKILL:
- packet.FailedArg1 = 0; // SkillLine.dbc id
- packet.FailedArg2 = 0; // required skill value
+ if (param1 && param2)
+ {
+ packet.FailedArg1 = *param1;
+ packet.FailedArg2 = *param2;
+ }
+ else
+ {
+ packet.FailedArg1 = 0; // SkillLine.dbc id
+ packet.FailedArg2 = 0; // required skill value
+ }
break;
case SPELL_FAILED_FISHING_TOO_LOW:
- packet.FailedArg1 = 0; // required fishing skill
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // required fishing skill
break;
case SPELL_FAILED_CUSTOM_ERROR:
packet.FailedArg1 = customError;
break;
case SPELL_FAILED_SILENCED:
- packet.FailedArg1 = 0; // Unknown
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
+ packet.FailedArg1 = 0; // Unknown
break;
case SPELL_FAILED_REAGENTS:
{
- uint32 missingItem = 0;
- for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ if (param1)
+ packet.FailedArg1 = *param1;
+ else
{
- if (spellInfo->Reagent[i] <= 0)
- continue;
+ uint32 missingItem = 0;
+ for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
+ {
+ if (spellInfo->Reagent[i] <= 0)
+ continue;
- uint32 itemid = spellInfo->Reagent[i];
- uint32 itemcount = spellInfo->ReagentCount[i];
+ uint32 itemid = spellInfo->Reagent[i];
+ uint32 itemcount = spellInfo->ReagentCount[i];
- if (!caster->HasItemCount(itemid, itemcount))
- {
- missingItem = itemid;
- break;
+ if (!caster->HasItemCount(itemid, itemcount))
+ {
+ missingItem = itemid;
+ break;
+ }
}
+ packet.FailedArg1 = missingItem; // first missing item
}
-
- packet.FailedArg1 = missingItem; // first missing item
break;
}
case SPELL_FAILED_CANT_UNTALENT:
{
- if (misc)
- if (TalentEntry const* talent = sTalentStore.LookupEntry(misc[0]))
- packet.FailedArg1 = talent->SpellID;
+ ASSERT(param1);
+ packet.FailedArg1 = *param1;
break;
}
// TODO: SPELL_FAILED_NOT_STANDING
@@ -3902,7 +3980,7 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons
}
}
-void Spell::SendCastResult(SpellCastResult result)
+void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
if (result == SPELL_CAST_OK)
return;
@@ -3910,7 +3988,7 @@ void Spell::SendCastResult(SpellCastResult result)
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- if (m_caster->ToPlayer()->GetSession()->PlayerLoading()) // don't send cast results at loading time
+ if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time
return;
if (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR)
@@ -3918,11 +3996,11 @@ void Spell::SendCastResult(SpellCastResult result)
WorldPackets::Spells::CastFailed castFailed;
castFailed.SpellXSpellVisualID = m_SpellVisual;
- FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, m_misc.Raw.Data, m_caster->ToPlayer());
+ FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster->ToPlayer());
m_caster->ToPlayer()->SendDirectMessage(castFailed.Write());
}
-void Spell::SendPetCastResult(SpellCastResult result)
+void Spell::SendPetCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
if (result == SPELL_CAST_OK)
return;
@@ -3935,18 +4013,18 @@ void Spell::SendPetCastResult(SpellCastResult result)
result = SPELL_FAILED_DONT_REPORT;
WorldPackets::Spells::PetCastFailed petCastFailed;
- FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, m_misc.Raw.Data, owner->ToPlayer());
+ FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, param1, param2, owner->ToPlayer());
owner->ToPlayer()->SendDirectMessage(petCastFailed.Write());
}
-void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* misc /*= nullptr*/)
+void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint32 spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
if (result == SPELL_CAST_OK)
return;
WorldPackets::Spells::CastFailed packet;
packet.SpellXSpellVisualID = spellVisual;
- FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, misc, caster);
+ FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster);
caster->GetSession()->SendPacket(packet.Write());
}
@@ -4605,7 +4683,7 @@ void Spell::TakePower()
}
}
-SpellCastResult Spell::CheckRuneCost()
+SpellCastResult Spell::CheckRuneCost() const
{
int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
{
@@ -4785,7 +4863,7 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT
}
}
-SpellCastResult Spell::CheckCast(bool strict)
+SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
{
// check death state
if (!m_caster->IsAlive() && !m_spellInfo->IsPassive() && !(m_spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD) || (IsTriggered() && !m_triggeredByAuraSpell)))
@@ -4848,13 +4926,15 @@ SpellCastResult Spell::CheckCast(bool strict)
bool checkForm = true;
// Ignore form req aura
Unit::AuraEffectList const& ignore = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
- for (Unit::AuraEffectList::const_iterator i = ignore.begin(); i != ignore.end(); ++i)
+ for (AuraEffect const* aurEff : ignore)
{
- if (!(*i)->IsAffectingSpell(m_spellInfo))
+ if (!aurEff->IsAffectingSpell(m_spellInfo))
continue;
+
checkForm = false;
break;
}
+
if (checkForm)
{
// Cannot be used in this stance/form
@@ -5076,7 +5156,7 @@ SpellCastResult Spell::CheckCast(bool strict)
// always (except passive spells) check items (only player related checks)
if (!m_spellInfo->IsPassive())
{
- castResult = CheckItems();
+ castResult = CheckItems(param1, param2);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5096,7 +5176,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_AURAS))
{
- castResult = CheckCasterAuras();
+ castResult = CheckCasterAuras(param1);
if (castResult != SPELL_CAST_OK)
return castResult;
}
@@ -5567,7 +5647,11 @@ SpellCastResult Spell::CheckCast(bool strict)
if (!talent)
return SPELL_FAILED_DONT_REPORT;
if (m_caster->GetSpellHistory()->HasCooldown(talent->SpellID))
+ {
+ if (param1)
+ *param1 = talent->SpellID;
return SPELL_FAILED_CANT_UNTALENT;
+ }
break;
}
case SPELL_EFFECT_GIVE_ARTIFACT_POWER:
@@ -5780,142 +5864,110 @@ SpellCastResult Spell::CheckPetCast(Unit* target)
return CheckCast(true);
}
-SpellCastResult Spell::CheckCasterAuras() const
+SpellCastResult Spell::CheckCasterAuras(uint32* param1) const
{
// spells totally immuned to caster auras (wsg flag drop, give marks etc)
if (m_spellInfo->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_AURAS))
return SPELL_CAST_OK;
- uint8 school_immune = 0;
- uint32 mechanic_immune = 0;
- uint32 dispel_immune = 0;
-
- // Check if the spell grants school or mechanic immunity.
- // We use bitmasks so the loop is done only once and not on every aura check below.
- if (m_spellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
+ bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED);
+ bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED);
+ if (m_spellInfo->HasAttribute(SPELL_ATTR7_USABLE_IN_STUN_FEAR_CONFUSION))
{
- for (SpellEffectInfo const* effect : GetEffects())
- {
- if (!effect)
- continue;
-
- if (effect->ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY)
- school_immune |= uint32(effect->MiscValue);
- else if (effect->ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY)
- mechanic_immune |= 1 << uint32(effect->MiscValue);
- else if (effect->ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY)
- dispel_immune |= SpellInfo::GetDispelMask(DispelType(effect->MiscValue));
- }
- // immune movement impairment and loss of control
- if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574 || m_spellInfo->Id == 53490)
- mechanic_immune = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
+ usableWhileStunned = true;
+ usableWhileFeared = true;
+ usableWhileConfused = true;
}
- bool usableInStun = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
-
// Check whether the cast should be prevented by any state you might have.
- SpellCastResult prevented_reason = SPELL_CAST_OK;
- // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out
- uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state
- if (unitflag & UNIT_FLAG_STUNNED)
- {
- // spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell
- if (usableInStun)
- {
- static uint32 const allowedStunMask =
- 1 << MECHANIC_STUN
- | 1 << MECHANIC_FREEZE
- | 1 << MECHANIC_SAPPED
- | 1 << MECHANIC_SLEEP;
-
- bool foundNotStun = false;
- Unit::AuraEffectList const& stunAuras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_STUN);
- for (Unit::AuraEffectList::const_iterator i = stunAuras.begin(); i != stunAuras.end(); ++i)
- {
- uint32 mechanicMask = (*i)->GetSpellInfo()->GetAllEffectsMechanicMask();
- if (mechanicMask && !(mechanicMask & allowedStunMask))
- {
- foundNotStun = true;
- break;
- }
- }
- if (foundNotStun)
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else
- prevented_reason = SPELL_FAILED_STUNNED;
- }
- else if (unitflag & UNIT_FLAG_CONFUSED && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- prevented_reason = SPELL_FAILED_CONFUSED;
- else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- prevented_reason = SPELL_FAILED_FLEEING;
- else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
- prevented_reason = SPELL_FAILED_SILENCED;
- else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY)
- prevented_reason = SPELL_FAILED_PACIFIED;
+ SpellCastResult result = SPELL_CAST_OK;
+
+ // Get unit state
+ uint32 const unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS);
+ if (!m_caster->GetCharmerGUID().IsEmpty())
+ {
+ if (Unit* charmer = m_caster->GetCharmer())
+ if (charmer->GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(param1))
+ result = SPELL_FAILED_CHARMED;
+ }
+ else if (unitflag & UNIT_FLAG_STUNNED && !usableWhileStunned && CheckCasterNotImmunedStunAuras(param1))
+ result = SPELL_FAILED_STUNNED;
+ else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE && CheckCasterNotImmunedSilenceAuras(param1))
+ result = SPELL_FAILED_SILENCED;
+ else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY && CheckCasterNotImmunedPacifyAuras(param1))
+ result = SPELL_FAILED_PACIFIED;
+ else if (unitflag & UNIT_FLAG_FLEEING && !usableWhileFeared && CheckCasterNotImmunedFearAuras(param1))
+ result = SPELL_FAILED_FLEEING;
+ else if (unitflag & UNIT_FLAG_CONFUSED && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(param1))
+ result = SPELL_FAILED_CONFUSED;
else if (m_caster->HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_NO_ACTIONS) && m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_NO_ACTIONS)
- prevented_reason = SPELL_FAILED_NO_ACTIONS;
+ result = SPELL_FAILED_NO_ACTIONS;
// Attr must make flag drop spell totally immune from all effects
- if (prevented_reason != SPELL_CAST_OK)
- {
- if (school_immune || mechanic_immune || dispel_immune)
- {
- //Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
- Unit::AuraApplicationMap const& auras = m_caster->GetAppliedAuras();
- for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- Aura const* aura = itr->second->GetBase();
- SpellInfo const* auraInfo = aura->GetSpellInfo();
- if (auraInfo->GetAllEffectsMechanicMask() & mechanic_immune)
- continue;
- if (auraInfo->GetSchoolMask() & school_immune && !auraInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE))
- continue;
- if (auraInfo->GetDispelMask() & dispel_immune)
- continue;
+ if (result != SPELL_CAST_OK)
+ return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
- //Make a second check for spell failed so the right SPELL_FAILED message is returned.
- //That is needed when your casting is prevented by multiple states and you are only immune to some of them.
- for (SpellEffectInfo const* effect : GetEffects())
- {
- if (!effect)
- continue;
+ return SPELL_CAST_OK;
+}
- if (AuraEffect* part = aura->GetEffect(effect->EffectIndex))
- {
- switch (part->GetAuraType())
- {
- case SPELL_AURA_MOD_STUN:
- if (!usableInStun || !(auraInfo->GetAllEffectsMechanicMask() & (1<<MECHANIC_STUN)))
- return SPELL_FAILED_STUNNED;
- break;
- case SPELL_AURA_MOD_CONFUSE:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED))
- return SPELL_FAILED_CONFUSED;
- break;
- case SPELL_AURA_MOD_FEAR:
- if (!m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED))
- return SPELL_FAILED_FLEEING;
- break;
- case SPELL_AURA_MOD_SILENCE:
- case SPELL_AURA_MOD_PACIFY:
- case SPELL_AURA_MOD_PACIFY_SILENCE:
- if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_PACIFY)
- return SPELL_FAILED_PACIFIED;
- else if (m_spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
- return SPELL_FAILED_SILENCED;
- break;
- default: break;
- }
- }
- }
- }
+// based on sub_00804430 from 12340 client
+bool Spell::CheckCasterHasNotImmunedAuraType(AuraType auraType, uint32* param1) const
+{
+ // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
+ Unit::AuraEffectList const& auraEffects = m_caster->GetAuraEffectsByType(auraType);
+ if (auraEffects.empty())
+ return false;
+
+ for (AuraEffect const* aurEff : auraEffects)
+ {
+ if (m_spellInfo->CanSpellCastOverrideAuraEffect(aurEff))
+ continue;
+
+ if (param1)
+ {
+ *param1 = aurEff->GetSpellEffectInfo()->Mechanic;
+ if (!*param1)
+ *param1 = aurEff->GetSpellInfo()->Mechanic;
}
- // You are prevented from casting and the spell cast does not grant immunity. Return a failed error.
- else
- return prevented_reason;
+ return true;
}
- return SPELL_CAST_OK;
+
+ return false;
+}
+
+bool Spell::CheckCasterNotImmunedCharmAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_AOE_CHARM, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_POSSESS, param1);
+}
+
+bool Spell::CheckCasterNotImmunedStunAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_STUN, param1);
+}
+
+bool Spell::CheckCasterNotImmunedSilenceAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_SILENCE, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedPacifyAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY, param1) ||
+ CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_PACIFY_SILENCE, param1);
+}
+
+bool Spell::CheckCasterNotImmunedFearAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_FEAR, param1);
+}
+
+bool Spell::CheckCasterNotImmunedDisorientAuras(uint32* param1) const
+{
+ return CheckCasterHasNotImmunedAuraType(SPELL_AURA_MOD_CONFUSE, param1);
}
SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
@@ -6025,7 +6077,7 @@ void Spell::CheckDst()
m_targets.SetDst(*m_caster);
}
-SpellCastResult Spell::CheckRange(bool strict)
+SpellCastResult Spell::CheckRange(bool strict) const
{
// Don't check for instant cast spells
if (!strict && m_casttime == 0)
@@ -6064,7 +6116,7 @@ SpellCastResult Spell::CheckRange(bool strict)
return SPELL_CAST_OK;
}
-std::pair<float, float> Spell::GetMinMaxRange(bool strict)
+std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
{
float rangeMod = 0.0f;
float minRange = 0.0f;
@@ -6110,14 +6162,14 @@ std::pair<float, float> Spell::GetMinMaxRange(bool strict)
maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
if (Player* modOwner = m_caster->GetSpellModOwner())
- modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
+ modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, const_cast<Spell*>(this));
maxRange += rangeMod;
return std::pair<float, float>(minRange, maxRange);
}
-SpellCastResult Spell::CheckPower()
+SpellCastResult Spell::CheckPower() const
{
// item cast not used power
if (m_CastItem)
@@ -6155,12 +6207,15 @@ SpellCastResult Spell::CheckPower()
return SPELL_CAST_OK;
}
-SpellCastResult Spell::CheckItems()
+SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
{
Player* player = m_caster->ToPlayer();
if (!player)
return SPELL_CAST_OK;
+ if (m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_ITEM_CHECK))
+ return SPELL_CAST_OK;
+
if (!m_CastItem)
{
if (!m_castItemGUID.IsEmpty())
@@ -6236,10 +6291,11 @@ SpellCastResult Spell::CheckItems()
// check target item
if (!m_targets.GetItemTargetGUID().IsEmpty())
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_ITEM_GONE;
- if (!m_targets.GetItemTarget()->IsFitToSpellRequirements(m_spellInfo))
+ if (!item->IsFitToSpellRequirements(m_spellInfo))
return SPELL_FAILED_EQUIPPED_ITEM_CLASS;
}
// if not item target then required item must be equipped
@@ -6289,7 +6345,11 @@ SpellCastResult Spell::CheckItems()
}
}
if (!player->HasItemCount(itemid, itemcount))
+ {
+ if (param1)
+ *param1 = itemid;
return SPELL_FAILED_REAGENTS;
+ }
}
}
@@ -6496,21 +6556,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_PROSPECTING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_PROSPECTED;
//ensure item is a prospectable ore
- if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
+ if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_PROSPECTABLE))
return SPELL_FAILED_CANT_BE_PROSPECTED;
//prevent prospecting in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_PROSPECTED;
//Check for enough skill in jewelcrafting
- uint32 item_prospectingskilllevel = m_targets.GetItemTarget()->GetTemplate()->GetRequiredSkillRank();
- if (item_prospectingskilllevel >player->GetSkillValue(SKILL_JEWELCRAFTING))
+ uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
+ if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required ores in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Prospecting.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_PROSPECTED;
@@ -6519,21 +6587,29 @@ SpellCastResult Spell::CheckItems()
}
case SPELL_EFFECT_MILLING:
{
- if (!m_targets.GetItemTarget())
+ Item* item = m_targets.GetItemTarget();
+ if (!item)
return SPELL_FAILED_CANT_BE_MILLED;
//ensure item is a millable herb
- if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
+ if (!(item->GetTemplate()->GetFlags() & ITEM_FLAG_IS_MILLABLE))
return SPELL_FAILED_CANT_BE_MILLED;
//prevent milling in trade slot
- if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID())
+ if (item->GetOwnerGUID() != m_caster->GetGUID())
return SPELL_FAILED_CANT_BE_MILLED;
//Check for enough skill in inscription
- uint32 item_millingskilllevel = m_targets.GetItemTarget()->GetTemplate()->GetRequiredSkillRank();
+ uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
return SPELL_FAILED_LOW_CASTLEVEL;
//make sure the player has the required herbs in inventory
- if (m_targets.GetItemTarget()->GetCount() < 5)
+ if (item->GetCount() < 5)
+ {
+ if (param1 && param2)
+ {
+ *param1 = item->GetEntry();
+ *param2 = 5;
+ }
return SPELL_FAILED_NEED_MORE_ITEMS;
+ }
if (!LootTemplates_Milling.HaveLootFor(m_targets.GetItemTargetEntry()))
return SPELL_FAILED_CANT_BE_MILLED;