diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index c011013fc..551b4493d 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -44,6 +44,8 @@ #include "BattleGround.h" #include "Util.h" #include "Chat.h" +#include "DB2Stores.h" +#include "SQLStorages.h" extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -102,8 +104,10 @@ bool IsQuestTameSpell(uint32 spellId) if (!spellproto) return false; - return spellproto->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_THREAT - && spellproto->Effect[EFFECT_INDEX_1] == SPELL_EFFECT_APPLY_AURA && spellproto->EffectApplyAuraName[EFFECT_INDEX_1] == SPELL_AURA_DUMMY; + SpellEffectEntry const* spellEffect0 = spellproto->GetSpellEffect(EFFECT_INDEX_0); + SpellEffectEntry const* spellEffect1 = spellproto->GetSpellEffect(EFFECT_INDEX_1); + return spellEffect0 && spellEffect0->Effect == SPELL_EFFECT_THREAT && + spellEffect1 && spellEffect1->Effect == SPELL_EFFECT_APPLY_AURA && spellEffect1->EffectApplyAuraName == SPELL_AURA_DUMMY; } SpellCastTargets::SpellCastTargets() @@ -117,6 +121,9 @@ SpellCastTargets::SpellCastTargets() m_srcX = m_srcY = m_srcZ = m_destX = m_destY = m_destZ = 0.0f; m_strTarget = ""; m_targetMask = 0; + + m_elevation = 0.0f; + m_speed = 0.0f; } SpellCastTargets::~SpellCastTargets() @@ -310,6 +317,44 @@ void SpellCastTargets::write(ByteBuffer& data) const data << m_strTarget; } +void SpellCastTargets::ReadAdditionalData(WorldPacket& data, uint8& cast_flags) +{ + if (cast_flags & 0x02) // has trajectory data + { + data >> m_elevation >> m_speed; + + bool hasMovementData; + data >> hasMovementData; + if (hasMovementData) + { + MovementInfo mi; + data >> mi; + setSource(mi.GetPos()->x, mi.GetPos()->y, mi.GetPos()->z); + } + } + else if (cast_flags & 0x08) // has archaeology weight + { + uint32 count; + uint8 type; + data >> count; + for (uint32 i = 0; i < count; ++i) + { + data >> type; + switch (type) + { + case 1: // Fragments + data >> Unused(); // Currency entry + data >> Unused(); // Currency count + break; + case 2: // Keystones + data >> Unused(); // Item entry + data >> Unused(); // Item count + break; + } + } + } +} + Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid originalCasterGUID, SpellEntry const* triggeredBy) { MANGOS_ASSERT(caster != NULL && info != NULL); @@ -326,6 +371,9 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or m_spellInfo = info; m_triggeredBySpellInfo = triggeredBy; + + m_spellInterrupts = m_spellInfo->GetSpellInterrupts(); + m_caster = caster; m_selfContainer = NULL; m_referencedFromCurrentSpell = false; @@ -346,7 +394,7 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or if ((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId() == TYPEID_PLAYER) { if (Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK)) - m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType); + m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->DamageType); } } // Set health leech amount to zero @@ -392,14 +440,17 @@ Spell::Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid or m_spellFlags = SPELL_FLAG_NORMAL; - if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR_EX2_CANT_REFLECTED)) + if (m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_MAGIC && !m_spellInfo->HasAttribute(SPELL_ATTR_EX2_CANT_REFLECTED)) { for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - if (m_spellInfo->Effect[j] == 0) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect) + continue; + if (spellEffect->Effect == 0) continue; - if (!IsPositiveTarget(m_spellInfo->EffectImplicitTargetA[j], m_spellInfo->EffectImplicitTargetB[j])) + if(!IsPositiveTarget(spellEffect->EffectImplicitTargetA, spellEffect->EffectImplicitTargetB)) m_canReflect = true; else m_canReflect = m_spellInfo->HasAttribute(SPELL_ATTR_EX_NEGATIVE); @@ -446,32 +497,40 @@ void Spell::FillTargetMap() uint8 effToIndex[MAX_EFFECT_INDEX] = {0, 1, 2}; // Helper array, to link to another tmpUnitList, if the targets for both effects match for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + // not call for empty effect. // Also some spells use not used effect targets for store targets for dummy effect in triggered spells - if (m_spellInfo->Effect[i] == SPELL_EFFECT_NONE) + if(spellEffect->Effect == SPELL_EFFECT_NONE) continue; // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT // for TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT (A) all is checked in Spell::CheckCast and in Spell::CheckItem // filled in Spell::CheckCast call - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || - (m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF)) + if(spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || + spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || + spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || + (spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF)) continue; // TODO: find a way so this is not needed? // for area auras always add caster as target (needed for totems for example) - if (IsAreaAuraEffect(m_spellInfo->Effect[i])) + if (IsAreaAuraEffect(spellEffect->Effect)) AddUnitTarget(m_caster, SpellEffectIndex(i)); // no double fill for same targets for (int j = 0; j < i; ++j) { + SpellEffectEntry const* spellEffect1 = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if (!spellEffect) + continue; + // Check if same target, but handle i.e. AreaAuras different - if (m_spellInfo->EffectImplicitTargetA[i] == m_spellInfo->EffectImplicitTargetA[j] && m_spellInfo->EffectImplicitTargetB[i] == m_spellInfo->EffectImplicitTargetB[j] - && m_spellInfo->Effect[j] != SPELL_EFFECT_NONE - && !IsAreaAuraEffect(m_spellInfo->Effect[i]) && !IsAreaAuraEffect(m_spellInfo->Effect[j])) + if (spellEffect->EffectImplicitTargetA == spellEffect1->EffectImplicitTargetA && spellEffect->EffectImplicitTargetB == spellEffect1->EffectImplicitTargetB + && spellEffect1->Effect != SPELL_EFFECT_NONE + && !IsAreaAuraEffect(spellEffect->Effect) && !IsAreaAuraEffect(spellEffect1->Effect)) // Add further conditions here if required { effToIndex[i] = j; // effect i has same targeting list as effect j @@ -483,10 +542,10 @@ void Spell::FillTargetMap() { // TargetA/TargetB dependent from each other, we not switch to full support this dependences // but need it support in some know cases - switch (m_spellInfo->EffectImplicitTargetA[i]) + switch(spellEffect->EffectImplicitTargetA) { case TARGET_NONE: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { case TARGET_NONE: if (m_caster->GetObjectGuid().IsPet()) @@ -495,39 +554,39 @@ void Spell::FillTargetMap() SetTargetMap(SpellEffectIndex(i), TARGET_EFFECT_SELECT, tmpUnitLists[i /*==effToIndex[i]*/]); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; case TARGET_SELF: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { case TARGET_NONE: case TARGET_EFFECT_SELECT: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); break; - case TARGET_AREAEFFECT_INSTANT: // use B case that not dependent from from A in fact - if ((m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) == 0) + case TARGET_AREAEFFECT_INSTANT: // use B case that not dependent from from A in fact + if((m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) == 0) m_targets.setDestination(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; - case TARGET_BEHIND_VICTIM: // use B case that not dependent from from A in fact - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + case TARGET_BEHIND_VICTIM: // use B case that not dependent from from A in fact + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; case TARGET_EFFECT_SELECT: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { case TARGET_NONE: case TARGET_EFFECT_SELECT: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); break; - // dest point setup required + // dest point setup required case TARGET_AREAEFFECT_INSTANT: case TARGET_AREAEFFECT_CUSTOM: case TARGET_ALL_ENEMY_IN_AREA: @@ -540,9 +599,9 @@ void Spell::FillTargetMap() if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) || m_IsTriggeredSpell) if (WorldObject* castObject = GetCastingObject()) m_targets.setDestination(castObject->GetPositionX(), castObject->GetPositionY(), castObject->GetPositionZ()); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; - // target pre-selection required + // target pre-selection required case TARGET_INNKEEPER_COORDINATES: case TARGET_TABLE_X_Y_Z_COORDINATES: case TARGET_CASTER_COORDINATES: @@ -559,108 +618,107 @@ void Spell::FillTargetMap() case TARGET_POINT_AT_SE: case TARGET_POINT_AT_SW: // need some target for processing - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; case TARGET_CASTER_COORDINATES: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { case TARGET_ALL_ENEMY_IN_AREA: // Note: this hack with search required until GO casting not implemented // environment damage spells already have around enemies targeting but this not help in case nonexistent GO casting support // currently each enemy selected explicitly and self cast damage - if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) + if (spellEffect->Effect == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) { - if (m_targets.getUnitTarget()) + if(m_targets.getUnitTarget()) tmpUnitLists[i /*==effToIndex[i]*/].push_back(m_targets.getUnitTarget()); } else { - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); } break; - case TARGET_NONE: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + case 0: + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); tmpUnitLists[i /*==effToIndex[i]*/].push_back(m_caster); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; case TARGET_TABLE_X_Y_Z_COORDINATES: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { - case TARGET_NONE: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + case 0: + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); - // need some target for processing + + // need some target for processing SetTargetMap(SpellEffectIndex(i), TARGET_EFFECT_SELECT, tmpUnitLists[i /*==effToIndex[i]*/]); break; - case TARGET_AREAEFFECT_INSTANT: // All 17/7 pairs used for dest teleportation, A processed in effect code - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + case TARGET_AREAEFFECT_INSTANT: // All 17/7 pairs used for dest teleportation, A processed in effect code + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); - break; + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); } - break; - case TARGET_SELF2: - switch (m_spellInfo->EffectImplicitTargetB[i]) + case TARGET_SELF2: + switch(spellEffect->EffectImplicitTargetB) { case TARGET_NONE: case TARGET_EFFECT_SELECT: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); break; case TARGET_AREAEFFECT_CUSTOM: // triggered spells get dest point from default target set, ignore it if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) || m_IsTriggeredSpell) if (WorldObject* castObject = GetCastingObject()) m_targets.setDestination(castObject->GetPositionX(), castObject->GetPositionY(), castObject->GetPositionZ()); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; - // most A/B target pairs is self->negative and not expect adding caster to target list + // most A/B target pairs is self->negative and not expect adding caster to target list default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; case TARGET_DUELVSPLAYER_COORDINATES: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { case TARGET_NONE: case TARGET_EFFECT_SELECT: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); if (Unit* currentTarget = m_targets.getUnitTarget()) tmpUnitLists[i /*==effToIndex[i]*/].push_back(currentTarget); break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; default: - switch (m_spellInfo->EffectImplicitTargetB[i]) + switch(spellEffect->EffectImplicitTargetB) { - case TARGET_NONE: + case 0: case TARGET_EFFECT_SELECT: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - break; - case TARGET_SCRIPT_COORDINATES: // B case filled in CheckCast but we need fill unit list base at A case - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); break; + case TARGET_SCRIPT_COORDINATES: // B case filled in CheckCast but we need fill unit list base at A case + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + break; default: - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetA[i], tmpUnitLists[i /*==effToIndex[i]*/]); - SetTargetMap(SpellEffectIndex(i), m_spellInfo->EffectImplicitTargetB[i], tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetA, tmpUnitLists[i /*==effToIndex[i]*/]); + SetTargetMap(SpellEffectIndex(i), spellEffect->EffectImplicitTargetB, tmpUnitLists[i /*==effToIndex[i]*/]); break; } break; @@ -718,14 +776,14 @@ void Spell::prepareDataForTriggerSystem() if (!m_canTrigger) // Exceptions (some periodic triggers) { - switch (m_spellInfo->SpellFamilyName) + switch (m_spellInfo->GetSpellFamilyName()) { case SPELLFAMILY_MAGE: - // Arcane Missiles / Blizzard triggers need do it + // Arcane Missles / Blizzard triggers need do it if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000000000200080))) m_canTrigger = true; // Clearcasting trigger need do it - else if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) + else if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000000200000000), 0x00000008)) m_canTrigger = true; // Replenish Mana, item spell with triggered cases (Mana Agate, etc mana gems) else if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000010000000000))) @@ -748,7 +806,7 @@ void Spell::prepareDataForTriggerSystem() break; case SPELLFAMILY_HUNTER: // Hunter Rapid Killing/Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect/Explosive Shot - if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0100200000000214), 0x00000200)) + if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0100200000000214), 0x200)) m_canTrigger = true; break; case SPELLFAMILY_PALADIN: @@ -762,7 +820,7 @@ void Spell::prepareDataForTriggerSystem() } // Get data for type of attack and fill base info for trigger - switch (m_spellInfo->DmgClass) + switch (m_spellInfo->GetDmgClass()) { case SPELL_DAMAGE_CLASS_MELEE: m_procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT; @@ -811,7 +869,7 @@ void Spell::prepareDataForTriggerSystem() // Hunter traps spells (for Entrapment trigger) // Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap .... - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x000020000000001C))) + if (m_spellInfo->IsFitToFamily(SPELLFAMILY_HUNTER, UI64LIT(0x000020000000001C))) m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION; } @@ -825,7 +883,8 @@ void Spell::CleanupTargetList() void Spell::AddUnitTarget(Unit* pVictim, SpellEffectIndex effIndex) { - if (m_spellInfo->Effect[effIndex] == 0) + SpellEffectEntry const *spellEffect = m_spellInfo->GetSpellEffect(effIndex); + if (!spellEffect || spellEffect->Effect == 0) return; // Check for effect immune skip if immuned @@ -861,8 +920,24 @@ void Spell::AddUnitTarget(Unit* pVictim, SpellEffectIndex effIndex) // spell fly from visual cast object WorldObject* affectiveObject = GetAffectiveCasterObject(); - // Spell have speed - need calculate incoming time - if (m_spellInfo->speed > 0.0f && affectiveObject && pVictim != affectiveObject) + // Spell has trajectory - need calculate incoming time + if (affectiveObject && m_targets.GetSpeed() > 0.0f) + { + float dist; + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + dist = affectiveObject->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + else + dist = affectiveObject->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); + float speed = m_targets.GetSpeed() * cos(m_targets.GetElevation()); + + target.timeDelay = (uint64) floor(dist / speed * 1000.0f); + + // Calculate minimum incoming time + if (m_delayMoment == 0 || m_delayMoment>target.timeDelay) + m_delayMoment = target.timeDelay; + } + // Spell has speed - need calculate incoming time + else if (m_spellInfo->speed > 0.0f && affectiveObject && pVictim != affectiveObject) { // calculate spell incoming interval float dist = affectiveObject->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); @@ -874,6 +949,15 @@ void Spell::AddUnitTarget(Unit* pVictim, SpellEffectIndex effIndex) if (m_delayMoment == 0 || m_delayMoment > target.timeDelay) m_delayMoment = target.timeDelay; } + // Spell casted on self - mostly TRIGGER_MISSILE code + else if (m_spellInfo->speed > 0.0f && affectiveObject && pVictim == affectiveObject) + { + float dist = 0.0f; + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + dist = affectiveObject->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + + target.timeDelay = (uint64) floor(dist / m_spellInfo->speed * 1000.0f); + } else target.timeDelay = UI64LIT(0); @@ -906,7 +990,8 @@ void Spell::AddUnitTarget(ObjectGuid unitGuid, SpellEffectIndex effIndex) void Spell::AddGOTarget(GameObject* pVictim, SpellEffectIndex effIndex) { - if (m_spellInfo->Effect[effIndex] == 0) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(effIndex); + if (!spellEffect || spellEffect->Effect == 0) return; ObjectGuid targetGUID = pVictim->GetObjectGuid(); @@ -931,8 +1016,24 @@ void Spell::AddGOTarget(GameObject* pVictim, SpellEffectIndex effIndex) // spell fly from visual cast object WorldObject* affectiveObject = GetAffectiveCasterObject(); - // Spell have speed - need calculate incoming time - if (m_spellInfo->speed > 0.0f && affectiveObject && pVictim != affectiveObject) + // Spell has trajectory - need calculate incoming time + if (affectiveObject && m_targets.GetSpeed() > 0.0f) + { + float dist; + if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) + dist = affectiveObject->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + else + dist = affectiveObject->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); + + float speed = m_targets.GetSpeed() * cos(m_targets.GetElevation()); + + target.timeDelay = (uint64) floor(dist / speed * 1000.0f); + + if (m_delayMoment == 0 || m_delayMoment > target.timeDelay) + m_delayMoment = target.timeDelay; + } + // Spell has speed - need calculate incoming time + else if (m_spellInfo->speed > 0.0f && affectiveObject && pVictim != affectiveObject) { // calculate spell incoming interval float dist = affectiveObject->GetDistance(pVictim->GetPositionX(), pVictim->GetPositionY(), pVictim->GetPositionZ()); @@ -957,7 +1058,8 @@ void Spell::AddGOTarget(ObjectGuid goGuid, SpellEffectIndex effIndex) void Spell::AddItemTarget(Item* pitem, SpellEffectIndex effIndex) { - if (m_spellInfo->Effect[effIndex] == 0) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(effIndex); + if (!spellEffect || spellEffect->Effect == 0) return; // Lookup target in already in list @@ -1117,28 +1219,29 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) caster->ProcDamageAndSpell(unitTarget, real_caster ? procAttacker : PROC_FLAG_NONE, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo); // trigger weapon enchants for weapon based spells; exclude spells that stop attack, because may break CC - if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->GetEquippedItemClass() == ITEM_CLASS_WEAPON && !m_spellInfo->HasAttribute(SPELL_ATTR_STOP_ATTACK_TARGET)) ((Player*)m_caster)->CastItemCombatSpell(unitTarget, m_attackType); // Haunt (NOTE: for avoid use additional field damage stored in dummy value (replace unused 100%) // apply before deal damage because aura can be removed at target kill - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellIconID == 3172 && - (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0004000000000000))) - if (Aura* dummy = unitTarget->GetDummyAura(m_spellInfo->Id)) + SpellClassOptionsEntry const *classOpt = m_spellInfo->GetSpellClassOptions(); + if (classOpt && classOpt->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellIconID == 3172 && + (classOpt->SpellFamilyFlags & UI64LIT(0x0004000000000000))) + if(Aura* dummy = unitTarget->GetDummyAura(m_spellInfo->Id)) dummy->GetModifier()->m_amount = damageInfo.damage; caster->DealSpellDamage(&damageInfo, true); // Scourge Strike, here because needs to use final damage in second part of the spell - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags & UI64LIT(0x0800000000000000)) + if (classOpt && classOpt->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && classOpt->SpellFamilyFlags & UI64LIT(0x0800000000000000)) { uint32 count = 0; Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap(); for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { - if (itr->second->GetSpellProto()->Dispel == DISPEL_DISEASE && - itr->second->GetCasterGuid() == caster->GetObjectGuid()) + if(itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE && + itr->second->GetCasterGuid() == caster->GetObjectGuid()) ++count; } @@ -1306,11 +1409,12 @@ void Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) { if (effectMask & (1 << effectNumber)) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(effectNumber)); HandleEffects(unit, NULL, NULL, SpellEffectIndex(effectNumber), m_damageMultipliers[effectNumber]); if (m_applyMultiplierMask & (1 << effectNumber)) { // Get multiplier - float multiplier = m_spellInfo->DmgMultiplier[effectNumber]; + float multiplier = spellEffect ? spellEffect->DmgMultiplier : 1.0f; // Apply multiplier mods if (realCaster) if (Player* modOwner = realCaster->GetSpellModOwner()) @@ -1428,11 +1532,12 @@ void Spell::HandleDelayedSpellLaunch(TargetInfo* target) { if (mask & (1 << effectNumber) && IsEffectHandledOnDelayedSpellLaunch(m_spellInfo, SpellEffectIndex(effectNumber))) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(effectNumber)); HandleEffects(unit, NULL, NULL, SpellEffectIndex(effectNumber), m_damageMultipliers[effectNumber]); if (m_applyMultiplierMask & (1 << effectNumber)) { // Get multiplier - float multiplier = m_spellInfo->DmgMultiplier[effectNumber]; + float multiplier = spellEffect ? spellEffect->DmgMultiplier : 1.0f; // Apply multiplier mods if (real_caster) if (Player* modOwner = real_caster->GetSpellModOwner()) @@ -1454,17 +1559,20 @@ void Spell::InitializeDamageMultipliers() { for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (m_spellInfo->Effect[i] == 0) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + if (spellEffect->Effect == 0) continue; - uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[i]; + uint32 EffectChainTarget = spellEffect->EffectChainTarget; if (Unit* realCaster = GetAffectiveCaster()) if (Player* modOwner = realCaster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, EffectChainTarget, this); m_damageMultipliers[i] = 1.0f; - if ((m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE || m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_HEAL) && - (EffectChainTarget > 1)) + if( (spellEffect->EffectImplicitTargetA == TARGET_CHAIN_DAMAGE || spellEffect->EffectImplicitTargetA == TARGET_CHAIN_HEAL) && + (EffectChainTarget > 1) ) m_applyMultiplierMask |= (1 << i); } } @@ -1563,13 +1671,16 @@ struct TargetDistanceOrderFarAway : public std::binary_functionGetSpellEffect(effIndex); + SpellClassOptionsEntry const* classOpt = m_spellInfo->GetSpellClassOptions(); + float radius; - if (m_spellInfo->EffectRadiusIndex[effIndex]) - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex])); + if (spellEffect && spellEffect->EffectRadiusIndex) + radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->EffectRadiusIndex)); else radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex)); - uint32 EffectChainTarget = m_spellInfo->EffectChainTarget[effIndex]; + uint32 EffectChainTarget = spellEffect ? spellEffect->EffectChainTarget : 0; if (Unit* realCaster = GetAffectiveCaster()) { @@ -1581,10 +1692,10 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& } // Get spell max affected targets - uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; + uint32 unMaxTargets = m_spellInfo->GetMaxAffectedTargets(); // custom target amount cases - switch (m_spellInfo->SpellFamilyName) + switch(m_spellInfo->GetSpellFamilyName()) { case SPELLFAMILY_GENERIC: { @@ -1604,7 +1715,6 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& case 50988: // Glare of the Tribunal (Halls of Stone) case 51146: // Searching Gaze (Halls Of Stone) case 52438: // Summon Skittering Swarmer (Azjol Nerub, Krik'thir the Gatewatcher) - case 53457: // Impale (Azjol Nerub, Anub'arak) case 54148: // Ritual of the Sword (Utgarde Pinnacle, Svala) case 55479: // Forced Obedience (Naxxramas, Razovius) case 56140: // Summon Power Spark (Eye of Eternity, Malygos) @@ -1753,11 +1863,14 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& { // overwrite EffectChainTarget for non single target spell if (Spell* currSpell = m_caster->GetCurrentSpell(CURRENT_GENERIC_SPELL)) - if (currSpell->m_spellInfo->MaxAffectedTargets > 0 || - currSpell->m_spellInfo->EffectChainTarget[EFFECT_INDEX_0] > 0 || - currSpell->m_spellInfo->EffectChainTarget[EFFECT_INDEX_1] > 0 || - currSpell->m_spellInfo->EffectChainTarget[EFFECT_INDEX_2] > 0) + { + for(int i = 0; i < MAX_EFFECT_INDEX; ++i) + if(SpellEffectEntry const* spellEffect = currSpell->m_spellInfo->GetSpellEffect(SpellEffectIndex(i))) + if(spellEffect->EffectChainTarget > 0) + EffectChainTarget = 0; // no chain targets + if (currSpell->m_spellInfo->GetMaxAffectedTargets() > 0) EffectChainTarget = 0; // no chain targets + } } break; default: @@ -1765,7 +1878,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& } // custom radius cases - switch (m_spellInfo->SpellFamilyName) + switch (m_spellInfo->GetSpellFamilyName()) { case SPELLFAMILY_GENERIC: { @@ -1774,7 +1887,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& case 24811: // Draw Spirit (Lethon) { if (effIndex == EFFECT_INDEX_0) // Copy range from EFF_1 to 0 - radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[EFFECT_INDEX_1])); + radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->EffectRadiusIndex)); break; } case 28241: // Poison (Naxxramas, Grobbulus Cloud) @@ -2032,7 +2145,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& unMaxTargets = EffectChainTarget; float max_range; - if (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE) + if(m_spellInfo->GetDmgClass() == SPELL_DAMAGE_CLASS_MELEE) max_range = radius; else // FIXME: This very like horrible hack and wrong for most spells @@ -2148,9 +2261,9 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& } case TARGET_AREAEFFECT_CUSTOM: { - if (m_spellInfo->Effect[effIndex] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + if (spellEffect && spellEffect->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) break; - else if (m_spellInfo->Effect[effIndex] == SPELL_EFFECT_SUMMON) + else if (spellEffect && spellEffect->Effect == SPELL_EFFECT_SUMMON) { targetUnitMap.push_back(m_caster); break; @@ -2248,7 +2361,10 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& case TARGET_ALL_ENEMY_IN_AREA_INSTANT: { // targets the ground, not the units in the area - switch (m_spellInfo->Effect[effIndex]) + if(!spellEffect) + break; + + switch(spellEffect->Effect) { case SPELL_EFFECT_PERSISTENT_AREA_AURA: break; @@ -2361,7 +2477,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& targetUnitMap.push_back(target); } // Circle of Healing - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellVisual[0] == 8253) + else if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_PRIEST && m_spellInfo->SpellVisual[0] == 8253) { Unit* target = m_targets.getUnitTarget(); if (!target) @@ -2375,7 +2491,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& FillRaidOrPartyHealthPriorityTargets(targetUnitMap, m_caster, target, radius, count, true, false, true); } // Wild Growth - else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864) + else if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_DRUID && m_spellInfo->SpellIconID == 2864) { Unit* target = m_targets.getUnitTarget(); if (!target) @@ -2500,11 +2616,11 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& break; case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: // targets the ground, not the units in the area - if (m_spellInfo->Effect[effIndex] != SPELL_EFFECT_PERSISTENT_AREA_AURA) + if (spellEffect && spellEffect->Effect!=SPELL_EFFECT_PERSISTENT_AREA_AURA) FillAreaTargets(targetUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE); break; case TARGET_MINION: - if (m_spellInfo->Effect[effIndex] != SPELL_EFFECT_DUEL) + if(spellEffect && spellEffect->Effect != SPELL_EFFECT_DUEL) targetUnitMap.push_back(m_caster); break; case TARGET_SINGLE_ENEMY: @@ -2698,7 +2814,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& // TODO - maybe use an (internal) value for the map for neat far teleport handling // far-teleport spells are handled in SpellEffect, elsewise report an error about an unexpected map (spells are always locally) - if (st->target_mapId != m_caster->GetMapId() && m_spellInfo->Effect[effIndex] != SPELL_EFFECT_TELEPORT_UNITS) + if (st->target_mapId != m_caster->GetMapId() && spellEffect && spellEffect->Effect != SPELL_EFFECT_TELEPORT_UNITS) sLog.outError("SPELL: wrong map (%u instead %u) target coordinates for spell ID %u", st->target_mapId, m_caster->GetMapId(), m_spellInfo->Id); } else @@ -2764,7 +2880,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& // "at the base of", in difference to 0 which appear to be "directly in front of". // TODO: some summoned will make caster be half inside summoned object. Need to fix // that in the below code (nearpoint vs closepoint, etc). - if (m_spellInfo->EffectRadiusIndex[effIndex] == 0) + if (!spellEffect || spellEffect->EffectRadiusIndex == 0) radius = 0.0f; if (m_spellInfo->Id == 50019) // Hawk Hunting, problematic 50K radius @@ -2841,7 +2957,10 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& { // add here custom effects that need default target. // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!! - switch (m_spellInfo->Effect[effIndex]) + if(!spellEffect) + break; + + switch(spellEffect->Effect) { case SPELL_EFFECT_DUMMY: { @@ -2904,7 +3023,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& if (m_targets.getUnitTarget()) targetUnitMap.push_back(m_targets.getUnitTarget()); // Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example) - else if (m_spellInfo->Effect[effIndex] == SPELL_EFFECT_TRIGGER_SPELL) + else if (spellEffect->Effect == SPELL_EFFECT_TRIGGER_SPELL) targetUnitMap.push_back(m_caster); break; case SPELL_EFFECT_SUMMON_PLAYER: @@ -2954,7 +3073,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& AddItemTarget(m_targets.getItemTarget(), effIndex); break; case SPELL_EFFECT_APPLY_AURA: - switch (m_spellInfo->EffectApplyAuraName[effIndex]) + switch(spellEffect->EffectApplyAuraName) { case SPELL_AURA_ADD_FLAT_MODIFIER: // some spell mods auras have 0 target modes instead expected TARGET_SELF(1) (and present for other ranks for same spell for example) case SPELL_AURA_ADD_PCT_MODIFIER: @@ -3258,17 +3377,31 @@ void Spell::cast(bool skipCheck) } } - // different triggered (for caster and main target after main cast) and pre-cast (casted before apply effect to each target) cases - switch (m_spellInfo->SpellFamilyName) + SpellClassOptionsEntry const* classOpt = m_spellInfo->GetSpellClassOptions(); + + // different triggered (for caster) and precast (casted before apply effect to target) cases + switch(m_spellInfo->GetSpellFamilyName()) { case SPELLFAMILY_GENERIC: { // Bandages - if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) + if (m_spellInfo->GetMechanic() == MECHANIC_BANDAGE) AddPrecastSpell(11196); // Recently Bandaged // Stoneskin else if (m_spellInfo->Id == 20594) AddTriggeredSpell(65116); // Stoneskin - armor 10% for 8 sec + else if (m_spellInfo->Id == 68992) // Darkflight + { + AddPrecastSpell(96223); // Run Speed Marker + AddPrecastSpell(97709); // Altered Form + } + else if (m_spellInfo->Id == 68996) // Two Forms + { + if (m_caster->IsInWorgenForm()) + m_caster->RemoveSpellsCausingAura(SPELL_AURA_WORGEN_TRANSFORM); + else + AddPrecastSpell(97709); // Altered Form + } // Chaos Bane strength buff else if (m_spellInfo->Id == 71904) AddTriggeredSpell(73422); @@ -3277,7 +3410,7 @@ void Spell::cast(bool skipCheck) case SPELLFAMILY_MAGE: { // Ice Block - if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000008000000000)) + if (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000008000000000)) AddPrecastSpell(41425); // Hypothermia // Icy Veins else if (m_spellInfo->Id == 12472) @@ -3297,13 +3430,13 @@ void Spell::cast(bool skipCheck) case SPELLFAMILY_WARRIOR: { // Shield Slam - if ((m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000020000000000)) && m_spellInfo->Category == 1209) + if (classOpt && (classOpt->SpellFamilyFlags & UI64LIT(0x0000020000000000)) && m_spellInfo->GetCategory()==1209) { if (m_caster->HasAura(58375)) // Glyph of Blocking AddTriggeredSpell(58374); // Glyph of Blocking } // Bloodrage - if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000100)) + if (classOpt && (classOpt->SpellFamilyFlags & UI64LIT(0x0000000000000100))) { if (m_caster->HasAura(70844)) // Item - Warrior T10 Protection 4P Bonus AddTriggeredSpell(70845); // Stoicism @@ -3319,11 +3452,11 @@ void Spell::cast(bool skipCheck) case SPELLFAMILY_PRIEST: { // Power Word: Shield - if (m_spellInfo->Mechanic == MECHANIC_SHIELD && - (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001))) + if (m_spellInfo->GetMechanic() == MECHANIC_SHIELD && + (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000000000000001))) AddPrecastSpell(6788); // Weakened Soul // Prayer of Mending (jump animation), we need formal caster instead original for correct animation - else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000002000000000)) + else if (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000002000000000)) AddTriggeredSpell(41637); switch (m_spellInfo->Id) @@ -3396,25 +3529,26 @@ void Spell::cast(bool skipCheck) AddPrecastSpell(67485); // Hand of Rekoning (no typos in name ;) ) } // Divine Shield, Divine Protection or Hand of Protection - else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000400080)) + else if (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000000000400080)) { AddPrecastSpell(25771); // Forbearance AddPrecastSpell(61987); // Avenging Wrath Marker } // Lay on Hands - else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000008000)) + else if (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000000000008000)) { // only for self cast if (m_caster == m_targets.getUnitTarget()) AddPrecastSpell(25771); // Forbearance } // Avenging Wrath - else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000200000000000)) + else if (classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000200000000000)) AddPrecastSpell(61987); // Avenging Wrath Marker break; } case SPELLFAMILY_SHAMAN: { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0); // Bloodlust if (m_spellInfo->Id == 2825) AddPrecastSpell(57724); // Sated @@ -3425,7 +3559,7 @@ void Spell::cast(bool skipCheck) else if (m_spellInfo->Id == 58875) AddPrecastSpell(58876); // Totem of Wrath - else if (m_spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_APPLY_AREA_AURA_RAID && m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000004000000)) + else if (spellEffect && spellEffect->Effect==SPELL_EFFECT_APPLY_AREA_AURA_RAID && classOpt && classOpt->SpellFamilyFlags & UI64LIT(0x0000000004000000)) // only for main totem spell cast AddTriggeredSpell(30708); // Totem of Wrath break; @@ -3599,18 +3733,19 @@ void Spell::_handle_immediate_phase() m_needSpellLog = IsNeedSendToClient(); for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - if (m_spellInfo->Effect[j] == 0) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect || spellEffect->Effect == 0) continue; // apply Send Event effect to ground in case empty target lists - if (m_spellInfo->Effect[j] == SPELL_EFFECT_SEND_EVENT && !HaveTargetsForEffect(SpellEffectIndex(j))) + if( spellEffect->Effect == SPELL_EFFECT_SEND_EVENT && !HaveTargetsForEffect(SpellEffectIndex(j)) ) { HandleEffects(NULL, NULL, NULL, SpellEffectIndex(j)); continue; } // Don't do spell log, if is school damage spell - if (m_spellInfo->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || m_spellInfo->Effect[j] == 0) + if(spellEffect->Effect == SPELL_EFFECT_SCHOOL_DAMAGE || spellEffect->Effect == 0) m_needSpellLog = false; } @@ -3625,8 +3760,11 @@ void Spell::_handle_immediate_phase() // process ground for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect) + continue; // persistent area auras target only the ground - if (m_spellInfo->Effect[j] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + if(spellEffect->Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) HandleEffects(NULL, NULL, NULL, SpellEffectIndex(j)); } } @@ -3671,16 +3809,19 @@ void Spell::update(uint32 difftime) return; } + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0); + SpellInterruptsEntry const* spellInterrupts = m_spellInfo->GetSpellInterrupts(); + // check if the player caster has moved before the spell finished if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && - (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) && - (m_spellInfo->Effect[EFFECT_INDEX_0] != SPELL_EFFECT_STUCK || !((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR))) + (m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) && + ((spellEffect && spellEffect->Effect != SPELL_EFFECT_STUCK) || !((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR))) { // always cancel for channeled spells if (m_spellState == SPELL_STATE_CASTING) cancel(); // don't cancel for melee, autorepeat, triggered and instant spells - else if (!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) + else if(!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell && (spellInterrupts && spellInterrupts->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) cancel(); } @@ -3714,7 +3855,7 @@ void Spell::update(uint32 difftime) cancel(); // check if player has turned if flag is set - if (m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation()) + if( spellInterrupts && (spellInterrupts->ChannelInterruptFlags & CHANNEL_FLAG_TURNING) && m_castOrientation != m_caster->GetOrientation() ) cancel(); } @@ -3810,8 +3951,9 @@ void Spell::finish(bool ok) // Calculate chance at that moment (can be depend for example from combo points) int32 auraBasePoints = (*i)->GetBasePoints(); int32 chance = m_caster->CalculateSpellDamage(unit, auraSpellInfo, auraSpellIdx, &auraBasePoints); - if (roll_chance_i(chance)) - m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i)); + if(roll_chance_i(chance)) + if(SpellEffectEntry const* spellEffect = auraSpellInfo->GetSpellEffect(auraSpellIdx)) + m_caster->CastSpell(unit, spellEffect->EffectTriggerSpell, true, NULL, (*i)); } } } @@ -3902,7 +4044,7 @@ void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 ca data << uint32(0); // unknown, value 1 seen for 14177 (update cooldowns on client flag) break; case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id + data << uint32(spellInfo->GetRequiresSpellFocus()); break; case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id // hardcode areas limitation case @@ -3925,21 +4067,37 @@ void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 ca } break; case SPELL_FAILED_TOTEMS: - for (int i = 0; i < MAX_SPELL_TOTEMS; ++i) - if (spellInfo->Totem[i]) - data << uint32(spellInfo->Totem[i]); // client needs only one id, not 2... + { + SpellTotemsEntry const* totems = spellInfo->GetSpellTotems(); + for(int i = 0; i < MAX_SPELL_TOTEMS; ++i) + if(totems && totems->Totem[i]) + data << uint32(totems->Totem[i]); + } break; case SPELL_FAILED_TOTEM_CATEGORY: - for (int i = 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i) - if (spellInfo->TotemCategory[i]) - data << uint32(spellInfo->TotemCategory[i]);// client needs only one id, not 2... + { + SpellTotemsEntry const* totems = spellInfo->GetSpellTotems(); + for(int i = 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i) + if(totems && totems->TotemCategory[i]) + data << uint32(totems->TotemCategory[i]); + } break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + { + SpellEquippedItemsEntry const* eqItems = spellInfo->GetSpellEquippedItems(); + data << uint32(eqItems ? eqItems->EquippedItemClass : 0); + data << uint32(eqItems ? eqItems->EquippedItemSubClassMask : 0); + //data << uint32(eqItems ? eqItems->EquippedItemInventoryTypeMask : 0); + } + break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: - data << uint32(spellInfo->EquippedItemClass); - data << uint32(spellInfo->EquippedItemSubClassMask); + { + SpellEquippedItemsEntry const* eqItems = spellInfo->GetSpellEquippedItems(); + data << uint32(eqItems ? eqItems->EquippedItemClass : 0); + data << uint32(eqItems ? eqItems->EquippedItemSubClassMask : 0); break; + } case SPELL_FAILED_PREVENTED_BY_MECHANIC: data << uint32(0); // SpellMechanic.dbc id break; @@ -3947,8 +4105,11 @@ void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 ca data << uint32(0); // custom error id (see enum SpellCastResultCustom) break; case SPELL_FAILED_NEED_EXOTIC_AMMO: - data << uint32(spellInfo->EquippedItemSubClassMask);// seems correct... + { + SpellEquippedItemsEntry const* eqItems = spellInfo->GetSpellEquippedItems(); + data << uint32(eqItems ? eqItems->EquippedItemSubClassMask : 0);// seems correct... break; + } case SPELL_FAILED_REAGENTS: data << uint32(0); // item id break; @@ -3980,12 +4141,14 @@ void Spell::SendSpellStart() DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Sending SMSG_SPELL_START id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_UNKNOWN2; - if (IsRangedSpell()) - castFlags |= CAST_FLAG_AMMO; - if (m_spellInfo->runeCostID) castFlags |= CAST_FLAG_UNKNOWN19; + if ((m_caster->GetTypeId() == TYPEID_PLAYER || + m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsPet()) && + m_spellInfo->powerType != POWER_HEALTH) + castFlags |= CAST_FLAG_PREDICTED_POWER; + WorldPacket data(SMSG_SPELL_START, (8 + 8 + 4 + 4 + 2)); if (m_CastItem) data << m_CastItem->GetPackGUID(); @@ -3997,24 +4160,30 @@ void Spell::SendSpellStart() data << uint32(m_spellInfo->Id); // spellId data << uint32(castFlags); // cast flags data << uint32(m_timer); // delay? + data << uint32(m_casttime); // m_casttime data << m_targets; if (castFlags & CAST_FLAG_PREDICTED_POWER) // predicted power - data << uint32(0); + data << uint32(m_caster->GetPower(Powers(m_spellInfo->powerType))); if (castFlags & CAST_FLAG_PREDICTED_RUNES) // predicted runes { - uint8 v1 = 0;// m_runesState; - uint8 v2 = 0;//((Player*)m_caster)->GetRunesState(); - data << uint8(v1); // runes state before - data << uint8(v2); // runes state after - for (uint8 i = 0; i < MAX_RUNES; ++i) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - uint8 m = (1 << i); - if (m & v1) // usable before... - if (!(m & v2)) // ...but on cooldown now... - data << uint8(0); // some unknown byte (time?) + Player* caster = (Player*)m_caster; + + data << uint8(m_runesState); + data << uint8(caster->GetRunesState()); + for (uint8 i = 0; i < MAX_RUNES; ++i) + data << uint8(255 - ((caster->GetRuneCooldown(i) / REGEN_TIME_FULL) * 51)); + } + else + { + data << uint8(0); + data << uint8(0); + for (uint8 i = 0; i < MAX_RUNES; ++i) + data << uint8(0); } } @@ -4027,6 +4196,15 @@ void Spell::SendSpellStart() data << uint32(0); // used for SetCastImmunities } + if (castFlags & CAST_FLAG_HEAL_PREDICTION) + { + uint8 unk = 0; + data << uint32(0); + data << uint8(unk); + if (unk == 2) + data << ObjectGuid().WriteAsPacked(); + } + m_caster->SendMessageToSet(&data, true); } @@ -4039,13 +4217,15 @@ void Spell::SendSpellGo() DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_UNKNOWN9; - if (IsRangedSpell()) - castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual - if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->getClass() == CLASS_DEATH_KNIGHT) && m_spellInfo->runeCostID) + if ((m_caster->GetTypeId() == TYPEID_PLAYER || + m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->IsPet()) && + m_spellInfo->powerType != POWER_HEALTH) + castFlags |= CAST_FLAG_PREDICTED_POWER; + + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_DEATH_KNIGHT && m_spellInfo->runeCostID) { castFlags |= CAST_FLAG_UNKNOWN19; // same as in SMSG_SPELL_START - castFlags |= CAST_FLAG_PREDICTED_POWER; // makes cooldowns visible castFlags |= CAST_FLAG_PREDICTED_RUNES; // rune cooldowns list } @@ -4060,6 +4240,7 @@ void Spell::SendSpellGo() data << uint8(m_cast_count); // pending spell cast? data << uint32(m_spellInfo->Id); // spellId data << uint32(castFlags); // cast flags + data << uint32(m_timer); data << uint32(WorldTimer::getMSTime()); // timestamp WriteSpellGoTargets(&data); @@ -4067,27 +4248,32 @@ void Spell::SendSpellGo() data << m_targets; if (castFlags & CAST_FLAG_PREDICTED_POWER) // predicted power - data << uint32(0); + data << uint32(m_caster->GetPower(Powers(m_spellInfo->powerType))); if (castFlags & CAST_FLAG_PREDICTED_RUNES) // predicted runes { - uint8 v1 = m_runesState; - uint8 v2 = m_caster->getClass() == CLASS_DEATH_KNIGHT ? ((Player*)m_caster)->GetRunesState() : 0; - data << uint8(v1); // runes state before - data << uint8(v2); // runes state after - for (uint8 i = 0; i < MAX_RUNES; ++i) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - uint8 m = (1 << i); - if (m & v1) // usable before... - if (!(m & v2)) // ...but on cooldown now... - data << uint8(0); // some unknown byte (time?) + Player* caster = (Player*)m_caster; + + data << uint8(m_runesState); + data << uint8(caster->GetRunesState()); + for (uint8 i = 0; i < MAX_RUNES; ++i) + data << uint8(255 - ((caster->GetRuneCooldown(i) / REGEN_TIME_FULL) * 51)); + } + else + { + data << uint8(0); + data << uint8(0); + for (uint8 i = 0; i < MAX_RUNES; ++i) + data << uint8(0); } } if (castFlags & CAST_FLAG_ADJUST_MISSILE) // adjust missile trajectory duration { - data << float(0); - data << uint32(0); + data << float(m_targets.GetElevation()); + data << uint32(m_delayMoment); } if (castFlags & CAST_FLAG_AMMO) // projectile info @@ -4133,17 +4319,7 @@ void Spell::WriteAmmoToPacket(WorldPacket* data) ammoDisplayID = pItem->GetProto()->DisplayInfoID; else { - uint32 ammoID = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); - if (ammoID) - { - ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(ammoID); - if (pProto) - { - ammoDisplayID = pProto->DisplayInfoID; - ammoInventoryType = pProto->InventoryType; - } - } - else if (m_caster->GetDummyAura(46699)) // Requires No Ammo + if(m_caster->GetDummyAura(46699)) // Requires No Ammo { ammoDisplayID = 5996; // normal arrow ammoInventoryType = INVTYPE_AMMO; @@ -4157,14 +4333,15 @@ void Spell::WriteAmmoToPacket(WorldPacket* data) { if (uint32 item_id = m_caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i)) { - if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id)) + if(ItemPrototype const* itemEntry = sItemStorage.LookupEntry(item_id)) + //if(ItemEntry const * itemEntry = sItemStore.LookupEntry(item_id)) { if (itemEntry->Class == ITEM_CLASS_WEAPON) { switch (itemEntry->SubClass) { case ITEM_SUBCLASS_WEAPON_THROWN: - ammoDisplayID = itemEntry->DisplayId; + ammoDisplayID = itemEntry->DisplayInfoID; ammoInventoryType = itemEntry->InventoryType; break; case ITEM_SUBCLASS_WEAPON_BOW: @@ -4255,14 +4432,19 @@ void Spell::SendLogExecute() data << uint32(count1); // count1 (effect count?) for (uint32 i = 0; i < count1; ++i) { - data << uint32(m_spellInfo->Effect[EFFECT_INDEX_0]);// spell effect + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0); + data << uint32(spellEffect ? spellEffect->Effect : 0);// spell effect uint32 count2 = 1; data << uint32(count2); // count2 (target count?) for (uint32 j = 0; j < count2; ++j) { - switch (m_spellInfo->Effect[EFFECT_INDEX_0]) + if(!spellEffect) + continue; + + switch(spellEffect->Effect) { case SPELL_EFFECT_POWER_DRAIN: + case SPELL_EFFECT_POWER_BURN: if (Unit* unit = m_targets.getUnitTarget()) data << unit->GetPackGUID(); else @@ -4300,8 +4482,9 @@ void Spell::SendLogExecute() data << uint8(0); break; case SPELL_EFFECT_CREATE_ITEM: + case SPELL_EFFECT_CREATE_RANDOM_ITEM: case SPELL_EFFECT_CREATE_ITEM_2: - data << uint32(m_spellInfo->EffectItemType[EFFECT_INDEX_0]); + data << uint32(spellEffect->EffectItemType); break; case SPELL_EFFECT_SUMMON: case SPELL_EFFECT_TRANS_DOOR: @@ -4310,9 +4493,10 @@ void Spell::SendLogExecute() case SPELL_EFFECT_CREATE_HOUSE: case SPELL_EFFECT_DUEL: case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: - case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: + //case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: + //case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: + //case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: + case SPELL_EFFECT_171: if (Unit* unit = m_targets.getUnitTarget()) data << unit->GetPackGUID(); else if (m_targets.getItemTargetGuid()) @@ -4333,6 +4517,7 @@ void Spell::SendLogExecute() break; case SPELL_EFFECT_RESURRECT: case SPELL_EFFECT_RESURRECT_NEW: + case SPELL_EFFECT_MASS_RESSURECTION: if (Unit* unit = m_targets.getUnitTarget()) data << unit->GetPackGUID(); else @@ -4413,7 +4598,7 @@ void Spell::SendChannelUpdate(uint32 time) m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); } - WorldPacket data(MSG_CHANNEL_UPDATE, 8 + 4); + WorldPacket data(SMSG_CHANNEL_UPDATE, 8 + 4); data << m_caster->GetPackGUID(); data << uint32(time); m_caster->SendMessageToSet(&data, true); @@ -4424,7 +4609,7 @@ void Spell::SendChannelStart(uint32 duration) WorldObject* target = NULL; // select dynobject created by first effect if any - if (m_spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_PERSISTENT_AREA_AURA) + if (m_spellInfo->GetSpellEffectIdByIndex(EFFECT_INDEX_0) == SPELL_EFFECT_PERSISTENT_AREA_AURA) target = m_caster->GetDynObject(m_spellInfo->Id, EFFECT_INDEX_0); // select first not resisted target from target list for _0_ effect else if (!m_UniqueTargetInfo.empty()) @@ -4451,10 +4636,26 @@ void Spell::SendChannelStart(uint32 duration) } } - WorldPacket data(MSG_CHANNEL_START, (8 + 4 + 4)); + WorldPacket data(SMSG_CHANNEL_START, (8 + 4 + 4)); data << m_caster->GetPackGUID(); data << uint32(m_spellInfo->Id); data << uint32(duration); + data << uint8(0); // unk1 + //if (unk1) + //{ + // data << uint32(0); + // data << uint32(0); + //} + data << uint8(0); // unk2 + //if (unk1) + //{ + // data << ObjectGuid().WriteAsPacked(); + // data << uint32(0); + // data << uint8(0); // unk3 + // if (unk3 == 2) + // data << ObjectGuid().WriteAsPacked(); + //} + m_caster->SendMessageToSet(&data, true); m_timer = duration; @@ -4488,9 +4689,9 @@ void Spell::SendPlaySpellVisual(uint32 SpellID) if (m_caster->GetTypeId() != TYPEID_PLAYER) return; - WorldPacket data(SMSG_PLAY_SPELL_VISUAL, 8 + 4); - data << m_caster->GetObjectGuid(); - data << uint32(SpellID); // spell visual id? + WorldPacket data; + m_caster->BuildSendPlayVisualPacket(&data, SpellID, false); + ((Player*)m_caster)->GetSession()->SendPacket(&data); } @@ -4694,13 +4895,17 @@ void Spell::TakeReagents() if (p_caster->CanNoReagentCast(m_spellInfo)) return; - for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x) + SpellReagentsEntry const* spellReagents = m_spellInfo->GetSpellReagents(); + + for(uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x) { - if (m_spellInfo->Reagent[x] <= 0) + if(!spellReagents) + continue; + if(spellReagents->Reagent[x] <= 0) continue; - uint32 itemid = m_spellInfo->Reagent[x]; - uint32 itemcount = m_spellInfo->ReagentCount[x]; + uint32 itemid = spellReagents->Reagent[x]; + uint32 itemcount = spellReagents->ReagentCount[x]; // if CastItem is also spell reagent if (m_CastItem) @@ -4748,8 +4953,9 @@ void Spell::HandleThreatSpells() bool positive = true; uint8 effectMask = 0; for (int i = 0; i < MAX_EFFECT_INDEX; ++i) - if (m_spellInfo->Effect[i]) - effectMask |= (1 << i); + if (SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i))) + if (spellEffect->Effect) + effectMask |= (1<Effect[i]; + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); damage = int32(CalculateDamage(i, unitTarget) * DamageMultiplier); - DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u Effect%d : %u Targets: %s, %s, %s", - m_spellInfo->Id, i, eff, - unitTarget ? unitTarget->GetGuidStr().c_str() : "-", - itemTarget ? itemTarget->GetGuidStr().c_str() : "-", - gameObjTarget ? gameObjTarget->GetGuidStr().c_str() : "-"); - - if (eff < TOTAL_SPELL_EFFECTS) + if(spellEffect) { - (*this.*SpellEffects[eff])(i); + if(spellEffect->Effect < TOTAL_SPELL_EFFECTS) + { + DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u Effect%d : %u Targets: %s, %s, %s", + m_spellInfo->Id, i, spellEffect->Effect, + unitTarget ? unitTarget->GetGuidStr().c_str() : "-", + itemTarget ? itemTarget->GetGuidStr().c_str() : "-", + gameObjTarget ? gameObjTarget->GetGuidStr().c_str() : "-"); + + (*this.*SpellEffects[spellEffect->Effect])(spellEffect); + } + else + { + sLog.outError("WORLD: Spell %u Effect%d : %u > TOTAL_SPELL_EFFECTS", m_spellInfo->Id, i, spellEffect->Effect); + } } else { - sLog.outError("WORLD: Spell FX %d > TOTAL_SPELL_EFFECTS ", eff); + sLog.outError("WORLD: Spell %u has no effect at index %u", m_spellInfo->Id, i); } } @@ -4915,25 +5128,27 @@ SpellCastResult Spell::CheckCast(bool strict) } } + SpellAuraRestrictionsEntry const* auraRestrictions = m_spellInfo->GetSpellAuraRestrictions(); + // caster state requirements - if (m_spellInfo->CasterAuraState && !m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraState))) + if(auraRestrictions && auraRestrictions->CasterAuraState && !m_caster->HasAuraState(AuraState(auraRestrictions->CasterAuraState))) return SPELL_FAILED_CASTER_AURASTATE; - if (m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot))) + if(auraRestrictions && auraRestrictions->CasterAuraStateNot && m_caster->HasAuraState(AuraState(auraRestrictions->CasterAuraStateNot))) return SPELL_FAILED_CASTER_AURASTATE; // Caster aura req check if need - if (m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell)) + if(auraRestrictions && auraRestrictions->casterAuraSpell && !m_caster->HasAura(auraRestrictions->casterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; - if (m_spellInfo->excludeCasterAuraSpell) + if(auraRestrictions && auraRestrictions->excludeCasterAuraSpell) { // Special cases of non existing auras handling - if (m_spellInfo->excludeCasterAuraSpell == 61988) + if(auraRestrictions->excludeCasterAuraSpell == 61988) { // Avenging Wrath Marker if (m_caster->HasAura(61987)) return SPELL_FAILED_CASTER_AURASTATE; } - else if (m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell)) + else if(m_caster->HasAura(auraRestrictions->excludeCasterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; } @@ -4944,40 +5159,44 @@ SpellCastResult Spell::CheckCast(bool strict) if (((Player*)m_caster)->isMoving()) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement - if ((!((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR) || m_spellInfo->Effect[EFFECT_INDEX_0] != SPELL_EFFECT_STUCK) && - (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0)) + if ((!((Player*)m_caster)->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLINGFAR) || m_spellInfo->GetSpellEffectIdByIndex(EFFECT_INDEX_0) != SPELL_EFFECT_STUCK) && + (IsAutoRepeat() || (m_spellInfo->GetAuraInterruptFlags() & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0)) return SPELL_FAILED_MOVING; } if (!m_IsTriggeredSpell && NeedsComboPoints(m_spellInfo) && !m_caster->IsIgnoreUnitState(m_spellInfo, IGNORE_UNIT_TARGET_STATE) && - (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetObjectGuid() != ((Player*)m_caster)->GetComboTargetGuid())) + (!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetObjectGuid() != ((Player*)m_caster)->GetComboTargetGuid()) && + !m_spellInfo->HasAttribute(SPELL_ATTR_EX8_IGNORE_TARGET_FOR_COMBO_POINTS)) // warrior not have real combo-points at client side but use this way for mark allow Overpower use return m_caster->getClass() == CLASS_WARRIOR ? SPELL_FAILED_CASTER_AURASTATE : SPELL_FAILED_NO_COMBO_POINTS; } - if (Unit* target = m_targets.getUnitTarget()) + SpellClassOptionsEntry const* classOptions = m_spellInfo->GetSpellClassOptions(); + + if(Unit *target = m_targets.getUnitTarget()) { // target state requirements (not allowed state), apply to self also - if (m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot))) + if(auraRestrictions && auraRestrictions->TargetAuraStateNot && target->HasAuraState(AuraState(auraRestrictions->TargetAuraStateNot))) return SPELL_FAILED_TARGET_AURASTATE; if (!m_IsTriggeredSpell && IsDeathOnlySpell(m_spellInfo) && target->isAlive()) return SPELL_FAILED_TARGET_NOT_DEAD; // Target aura req check if need - if (m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell)) + if(auraRestrictions && auraRestrictions->targetAuraSpell && !target->HasAura(auraRestrictions->targetAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; - if (m_spellInfo->excludeTargetAuraSpell) + + if(auraRestrictions && auraRestrictions->excludeTargetAuraSpell) { // Special cases of non existing auras handling - if (m_spellInfo->excludeTargetAuraSpell == 61988) + if (auraRestrictions->excludeTargetAuraSpell == 61988) { // Avenging Wrath Marker if (target->HasAura(61987)) return SPELL_FAILED_CASTER_AURASTATE; } - else if (target->HasAura(m_spellInfo->excludeTargetAuraSpell)) + else if (target->HasAura(auraRestrictions->excludeTargetAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; } @@ -4994,8 +5213,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (non_caster_target) { // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds - if (m_spellInfo->TargetAuraState && !target->HasAuraStateForCaster(AuraState(m_spellInfo->TargetAuraState), m_caster->GetObjectGuid()) && - !m_caster->IsIgnoreUnitState(m_spellInfo, m_spellInfo->TargetAuraState == AURA_STATE_FROZEN ? IGNORE_UNIT_TARGET_NON_FROZEN : IGNORE_UNIT_TARGET_STATE)) + if (auraRestrictions && auraRestrictions->TargetAuraState && !target->HasAuraStateForCaster(AuraState(auraRestrictions->TargetAuraState), m_caster->GetObjectGuid()) && + !m_caster->IsIgnoreUnitState(m_spellInfo, auraRestrictions->TargetAuraState == AURA_STATE_FROZEN ? IGNORE_UNIT_TARGET_NON_FROZEN : IGNORE_UNIT_TARGET_STATE)) return SPELL_FAILED_TARGET_AURASTATE; // Not allow casting on flying player @@ -5022,7 +5241,7 @@ SpellCastResult Spell::CheckCast(bool strict) // If 0 spell effect empty - client not send target data (need use selection) // TODO: check it on next client version if (m_targets.m_targetMask == TARGET_FLAG_SELF && - m_spellInfo->EffectImplicitTargetA[EFFECT_INDEX_1] == TARGET_CHAIN_DAMAGE) + m_spellInfo->GetEffectImplicitTargetAByIndex(EFFECT_INDEX_1) == TARGET_CHAIN_DAMAGE) { target = m_caster->GetMap()->GetUnit(((Player*)m_caster)->GetSelectionGuid()); if (!target) @@ -5035,8 +5254,8 @@ SpellCastResult Spell::CheckCast(bool strict) // Some special spells with non-caster only mode // Fire Shield - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && - m_spellInfo->SpellIconID == 16) + if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_WARLOCK && + m_spellInfo->SpellIconID == 16) return SPELL_FAILED_BAD_TARGETS; // Focus Magic (main spell) @@ -5044,8 +5263,8 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_BAD_TARGETS; // Lay on Hands (self cast) - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && - m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000008000)) + if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_PALADIN && + classOptions->SpellFamilyFlags & UI64LIT(0x0000000000008000)) { if (target->HasAura(25771)) // Forbearance return SPELL_FAILED_CASTER_AURASTATE; @@ -5057,7 +5276,11 @@ SpellCastResult Spell::CheckCast(bool strict) // check pet presents for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_PET) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect) + continue; + + if(spellEffect->EffectImplicitTargetA == TARGET_PET) { Pet* pet = m_caster->GetPet(); if (!pet) @@ -5093,7 +5316,10 @@ SpellCastResult Spell::CheckCast(bool strict) bool target_friendly_checked = false; for (int k = 0; k < MAX_EFFECT_INDEX; ++k) { - if (IsExplicitPositiveTarget(m_spellInfo->EffectImplicitTargetA[k])) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(k)); + if(!spellEffect) + continue; + if (IsExplicitPositiveTarget(spellEffect->EffectImplicitTargetA)) { if (!target_hostile_checked) { @@ -5106,7 +5332,7 @@ SpellCastResult Spell::CheckCast(bool strict) explicit_target_mode = true; } - else if (IsExplicitNegativeTarget(m_spellInfo->EffectImplicitTargetA[k])) + else if (IsExplicitNegativeTarget(spellEffect->EffectImplicitTargetA)) { if (!target_friendly_checked) { @@ -5212,24 +5438,28 @@ SpellCastResult Spell::CheckCast(bool strict) { for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || - (m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF) || - m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetA[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect) + continue; + + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || + (spellEffect->EffectImplicitTargetB == TARGET_SCRIPT && spellEffect->EffectImplicitTargetA != TARGET_SELF) || + spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || + spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES || + spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) { SpellScriptTargetBounds bounds = sSpellMgr.GetSpellScriptTargetBounds(m_spellInfo->Id); if (bounds.first == bounds.second) { - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT) sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT, but creature are not defined in `spell_script_target`", m_spellInfo->Id, j); - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES) sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT_COORDINATES, but gameobject or creature are not defined in `spell_script_target`", m_spellInfo->Id, j); - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) + if (spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) sLog.outErrorDb("Spell entry %u, effect %i has EffectImplicitTargetA/EffectImplicitTargetB = TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT, but gameobject are not defined in `spell_script_target`", m_spellInfo->Id, j); } @@ -5329,38 +5559,38 @@ SpellCastResult Spell::CheckCast(bool strict) if (creatureScriptTarget) { // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || + spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES) { m_targets.setDestination(creatureScriptTarget->GetPositionX(), creatureScriptTarget->GetPositionY(), creatureScriptTarget->GetPositionZ()); - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->Effect[j] != SPELL_EFFECT_PERSISTENT_AREA_AURA) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES && spellEffect->Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA) AddUnitTarget(creatureScriptTarget, SpellEffectIndex(j)); } // store explicit target for TARGET_SCRIPT else { - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT || + spellEffect->EffectImplicitTargetB == TARGET_SCRIPT) AddUnitTarget(creatureScriptTarget, SpellEffectIndex(j)); } } else if (goScriptTarget) { // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES || + spellEffect->EffectImplicitTargetB == TARGET_SCRIPT_COORDINATES) { m_targets.setDestination(goScriptTarget->GetPositionX(), goScriptTarget->GetPositionY(), goScriptTarget->GetPositionZ()); - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->Effect[j] != SPELL_EFFECT_PERSISTENT_AREA_AURA) + if (spellEffect->EffectImplicitTargetA == TARGET_SCRIPT_COORDINATES && spellEffect->Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA) AddGOTarget(goScriptTarget, SpellEffectIndex(j)); } // store explicit target for TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT else { - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) + if (spellEffect->EffectImplicitTargetA == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT || + spellEffect->EffectImplicitTargetB == TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) AddGOTarget(goScriptTarget, SpellEffectIndex(j)); } } @@ -5370,7 +5600,7 @@ SpellCastResult Spell::CheckCast(bool strict) /* For TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT makes DB targets optional not required for now * TODO: Makes more research for this target type */ - if (m_spellInfo->EffectImplicitTargetA[j] != TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) + if (spellEffect->EffectImplicitTargetA != TARGET_FOCUS_OR_SCRIPTED_GAMEOBJECT) { // not report target not existence for triggered spells if (m_triggeredByAuraSpell || m_IsTriggeredSpell) @@ -5405,8 +5635,11 @@ SpellCastResult Spell::CheckCast(bool strict) for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; // for effects of spells that have only one target - switch (m_spellInfo->Effect[i]) + switch(spellEffect->Effect) { case SPELL_EFFECT_INSTAKILL: // Death Pact @@ -5429,8 +5662,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (target->GetOwnerGuid() != m_caster->GetObjectGuid()) return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - if (!target->IsWithinDistInMap(m_caster, dist)) + float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->EffectRadiusIndex)); + if (!target->IsWithinDistInMap(m_caster,dist)) return SPELL_FAILED_OUT_OF_RANGE; // will set in target selection code @@ -5443,6 +5676,11 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->IsInWater()) return SPELL_FAILED_ONLY_ABOVEWATER; } + else if (m_spellInfo->Id == 68996) // Two forms + { + if (m_caster->isInCombat()) + return SPELL_FAILED_AFFECTING_COMBAT; + } else if (m_spellInfo->SpellIconID == 156) // Holy Shock { // spell different for friends and enemies @@ -5451,7 +5689,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_UNIT_NOT_INFRONT; } // Fire Nova - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellIconID == 33) + if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_SHAMAN && m_spellInfo->SpellIconID == 33) { // fire totems slot if (!m_caster->GetTotemGuid(TOTEM_SLOT_FIRE)) @@ -5533,7 +5771,7 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_LEARN_SPELL: { - if (m_spellInfo->EffectImplicitTargetA[i] != TARGET_PET) + if(spellEffect->EffectImplicitTargetA != TARGET_PET) break; Pet* pet = m_caster->GetPet(); @@ -5541,12 +5779,12 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet) return SPELL_FAILED_NO_PET; - SpellEntry const* learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(spellEffect->EffectTriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; - if (m_spellInfo->spellLevel > pet->getLevel()) + if(m_spellInfo->GetSpellLevel() > pet->getLevel()) return SPELL_FAILED_LOWLEVEL; break; @@ -5558,21 +5796,20 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet) return SPELL_FAILED_NO_PET; - SpellEntry const* learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]); - + SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(spellEffect->EffectTriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; - if (m_spellInfo->spellLevel > pet->getLevel()) + if(m_spellInfo->GetSpellLevel() > pet->getLevel()) return SPELL_FAILED_LOWLEVEL; break; } case SPELL_EFFECT_APPLY_GLYPH: { - uint32 glyphId = m_spellInfo->EffectMiscValue[i]; - if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId)) - if (m_caster->HasAura(gp->SpellId)) + uint32 glyphId = spellEffect->EffectMiscValue; + if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyphId)) + if(m_caster->HasAura(gp->SpellId)) return SPELL_FAILED_UNIQUE_GLYPH; break; } @@ -5607,7 +5844,7 @@ SpellCastResult Spell::CheckCast(bool strict) // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects) if (m_caster->GetTypeId() == TYPEID_PLAYER) if (Unit* target = m_targets.getUnitTarget()) - if (target != m_caster && int32(target->getPowerType()) != m_spellInfo->EffectMiscValue[i]) + if (target != m_caster && int32(target->getPowerType()) != spellEffect->EffectMiscValue) return SPELL_FAILED_BAD_TARGETS; break; } @@ -5654,7 +5891,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_BAD_TARGETS; // we need a go target in case of TARGET_GAMEOBJECT (for other targets acceptable GO and items) - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT) + if (spellEffect->EffectImplicitTargetA == TARGET_GAMEOBJECT) { if (!m_targets.getGOTarget()) return SPELL_FAILED_BAD_TARGETS; @@ -5723,7 +5960,7 @@ SpellCastResult Spell::CheckCast(bool strict) // This is generic summon effect case SPELL_EFFECT_SUMMON: { - if (SummonPropertiesEntry const* summon_prop = sSummonPropertiesStore.LookupEntry(m_spellInfo->EffectMiscValueB[i])) + if (SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(spellEffect->EffectMiscValueB)) { if (summon_prop->Group == SUMMON_PROP_GROUP_PETS) { @@ -5785,7 +6022,7 @@ SpellCastResult Spell::CheckCast(bool strict) case SPELL_EFFECT_LEAP: case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: { - float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEffect->EffectRadiusIndex)); float fx = m_caster->GetPositionX() + dis * cos(m_caster->GetOrientation()); float fy = m_caster->GetPositionY() + dis * sin(m_caster->GetOrientation()); // teleport a bit above terrain level to avoid falling below it @@ -5817,7 +6054,11 @@ SpellCastResult Spell::CheckCast(bool strict) for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { - switch (m_spellInfo->EffectApplyAuraName[i]) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + + switch(spellEffect->EffectApplyAuraName) { case SPELL_AURA_DUMMY: { @@ -5919,7 +6160,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_NO_MOUNTS_ALLOWED; // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells - if (m_caster->GetTypeId() == TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaGroupId) + if (m_caster->GetTypeId() == TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->GetAreaGroupId()) return SPELL_FAILED_NO_MOUNTS_ALLOWED; if (m_caster->IsInDisallowedMountForm()) @@ -6042,12 +6283,16 @@ SpellCastResult Spell::CheckPetCast(Unit* target) bool need = false; for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_FRIEND_2 || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_DUELVSPLAYER || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_PARTY || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_CURRENT_ENEMY_COORDINATES) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + + if (spellEffect->EffectImplicitTargetA == TARGET_CHAIN_DAMAGE || + spellEffect->EffectImplicitTargetA == TARGET_SINGLE_FRIEND || + spellEffect->EffectImplicitTargetA == TARGET_SINGLE_FRIEND_2 || + spellEffect->EffectImplicitTargetA == TARGET_DUELVSPLAYER || + spellEffect->EffectImplicitTargetA == TARGET_SINGLE_PARTY || + spellEffect->EffectImplicitTargetA == TARGET_CURRENT_ENEMY_COORDINATES) { need = true; if (!target) @@ -6075,8 +6320,8 @@ SpellCastResult Spell::CheckPetCast(Unit* target) bool duelvsplayertar = false; for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - // TARGET_DUELVSPLAYER is positive AND negative - duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER); + //TARGET_DUELVSPLAYER is positive AND negative + duelvsplayertar |= (m_spellInfo->GetEffectImplicitTargetAByIndex(SpellEffectIndex(j)) == TARGET_DUELVSPLAYER); } if (m_caster->IsFriendlyTo(target) && !duelvsplayertar) { @@ -6112,14 +6357,17 @@ SpellCastResult Spell::CheckCasterAuras() const { for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_SCHOOL_IMMUNITY) - school_immune |= uint32(m_spellInfo->EffectMiscValue[i]); - else if (m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY) - mechanic_immune |= 1 << uint32(m_spellInfo->EffectMiscValue[i] - 1); - else if (m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MECHANIC_IMMUNITY_MASK) - mechanic_immune |= uint32(m_spellInfo->EffectMiscValue[i]); - else if (m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_DISPEL_IMMUNITY) - dispel_immune |= GetDispellMask(DispelType(m_spellInfo->EffectMiscValue[i])); + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + if (spellEffect->EffectApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) + school_immune |= uint32(spellEffect->EffectMiscValue); + else if (spellEffect->EffectApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) + mechanic_immune |= 1 << uint32(spellEffect->EffectMiscValue-1); + else if (spellEffect->EffectApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY_MASK) + mechanic_immune |= uint32(spellEffect->EffectMiscValue); + else if (spellEffect->EffectApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) + dispel_immune |= GetDispellMask(DispelType(spellEffect->EffectMiscValue)); } // immune movement impairment and loss of control (spell data have special structure for mark this case) @@ -6136,7 +6384,7 @@ SpellCastResult Spell::CheckCasterAuras() const if (unitflag & UNIT_FLAG_STUNNED) { // Pain Suppression (have SPELL_ATTR_EX5_USABLE_WHILE_STUNNED that must be used only with glyph) - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellIconID == 2178) + if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_PRIEST && m_spellInfo->SpellIconID == 2178) { if (!m_caster->HasAura(63248)) // Glyph of Pain Suppression spellUsableWhileStunned = false; @@ -6163,9 +6411,9 @@ SpellCastResult Spell::CheckCasterAuras() const prevented_reason = SPELL_FAILED_CONFUSED; else if (unitflag & UNIT_FLAG_FLEEING && !m_spellInfo->HasAttribute(SPELL_ATTR_EX5_USABLE_WHILE_FEARED)) prevented_reason = SPELL_FAILED_FLEEING; - else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + else if (unitflag & UNIT_FLAG_SILENCED && m_spellInfo->GetPreventionType() == SPELL_PREVENTION_TYPE_SILENCE) prevented_reason = SPELL_FAILED_SILENCED; - else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) + else if (unitflag & UNIT_FLAG_PACIFIED && m_spellInfo->GetPreventionType() == SPELL_PREVENTION_TYPE_PACIFY) prevented_reason = SPELL_FAILED_PACIFIED; else if (m_caster->HasAuraType(SPELL_AURA_ALLOW_ONLY_ABILITY)) { @@ -6194,7 +6442,7 @@ SpellCastResult Spell::CheckCasterAuras() const if ((GetSpellSchoolMask(pEntry) & school_immune) && !pEntry->HasAttribute(SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE)) continue; - if ((1 << (pEntry->Dispel)) & dispel_immune) + if ((1<<(pEntry->GetDispel())) & dispel_immune) continue; for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) @@ -6224,9 +6472,9 @@ SpellCastResult Spell::CheckCasterAuras() const case SPELL_AURA_MOD_SILENCE: case SPELL_AURA_MOD_PACIFY: case SPELL_AURA_MOD_PACIFY_SILENCE: - if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_PACIFY) + if( m_spellInfo->GetPreventionType() == SPELL_PREVENTION_TYPE_PACIFY) return SPELL_FAILED_PACIFIED; - else if (m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + else if ( m_spellInfo->GetPreventionType() == SPELL_PREVENTION_TYPE_SILENCE) return SPELL_FAILED_SILENCED; break; default: break; @@ -6247,21 +6495,24 @@ bool Spell::CanAutoCast(Unit* target) for (int j = 0; j < MAX_EFFECT_INDEX; ++j) { - if (m_spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j)); + if(!spellEffect) + continue; + if(spellEffect->Effect == SPELL_EFFECT_APPLY_AURA) { - if (m_spellInfo->StackAmount <= 1) + if( m_spellInfo->GetStackAmount() <= 1) { if (target->HasAura(m_spellInfo->Id, SpellEffectIndex(j))) return false; } else { - if (Aura* aura = target->GetAura(m_spellInfo->Id, SpellEffectIndex(j))) - if (aura->GetStackAmount() >= m_spellInfo->StackAmount) + if(Aura* aura = target->GetAura(m_spellInfo->Id, SpellEffectIndex(j))) + if(aura->GetStackAmount() >= m_spellInfo->GetStackAmount()) return false; } } - else if (IsAreaAuraEffect(m_spellInfo->Effect[j])) + else if ( IsAreaAuraEffect( spellEffect->Effect )) { if (target->HasAura(m_spellInfo->Id, SpellEffectIndex(j))) return false; @@ -6333,8 +6584,8 @@ SpellCastResult Spell::CheckRange(bool strict) return SPELL_FAILED_OUT_OF_RANGE; if (min_range && dist < min_range) return SPELL_FAILED_TOO_CLOSE; - if (m_caster->GetTypeId() == TYPEID_PLAYER && - (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(M_PI_F, target)) + if( m_caster->GetTypeId() == TYPEID_PLAYER && + (m_spellInfo->GetFacingCasterFlags() & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc( M_PI_F, target ) ) return SPELL_FAILED_UNIT_NOT_INFRONT; } @@ -6370,24 +6621,23 @@ uint32 Spell::CalculatePowerCost(SpellEntry const* spellInfo, Unit* caster, Spel } // Base powerCost - int32 powerCost = spellInfo->manaCost; + int32 powerCost = spellInfo->GetManaCost(); // PCT cost from total amount - if (spellInfo->ManaCostPercentage) + if (uint32 manaCostPct = spellInfo->GetManaCostPercentage()) { switch (spellInfo->powerType) { // health as power used case POWER_HEALTH: - powerCost += spellInfo->ManaCostPercentage * caster->GetCreateHealth() / 100; + powerCost += manaCostPct * caster->GetCreateHealth() / 100; break; case POWER_MANA: - powerCost += spellInfo->ManaCostPercentage * caster->GetCreateMana() / 100; + powerCost += manaCostPct * caster->GetCreateMana() / 100; break; case POWER_RAGE: case POWER_FOCUS: case POWER_ENERGY: - case POWER_HAPPINESS: - powerCost += spellInfo->ManaCostPercentage * caster->GetMaxPower(Powers(spellInfo->powerType)) / 100; + powerCost += manaCostPct * caster->GetMaxPower(Powers(spellInfo->powerType)) / 100; break; case POWER_RUNE: case POWER_RUNIC_POWER: @@ -6410,7 +6660,7 @@ uint32 Spell::CalculatePowerCost(SpellEntry const* spellInfo, Unit* caster, Spel modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, powerCost, spell); if (spellInfo->HasAttribute(SPELL_ATTR_LEVEL_DAMAGE_CALCULATION)) - powerCost = int32(powerCost / (1.117f * spellInfo->spellLevel / caster->getLevel() - 0.1327f)); + powerCost = int32(powerCost / (1.117f * spellInfo->GetSpellLevel() / caster->getLevel() - 0.1327f)); // PCT mod from user auras by school powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school))); @@ -6480,8 +6730,12 @@ bool Spell::IgnoreItemRequirements() const /// Some triggered spells have same reagents that have master spell /// expected in test: master spell have reagents in first slot then triggered don't must use own - if (m_triggeredBySpellInfo && !m_triggeredBySpellInfo->Reagent[0]) - return false; + if (m_triggeredBySpellInfo) + { + SpellReagentsEntry const* spellReagents = m_triggeredBySpellInfo->GetSpellReagents(); + if (!spellReagents || !spellReagents->Reagent[0]) + return false; + } return true; } @@ -6527,11 +6781,14 @@ SpellCastResult Spell::CheckItems() SpellCastResult failReason = SPELL_CAST_OK; for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + if (spellEffect->EffectImplicitTargetA == TARGET_PET) continue; - if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) + if (spellEffect->Effect == SPELL_EFFECT_HEAL) { if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) { @@ -6546,15 +6803,15 @@ SpellCastResult Spell::CheckItems() } // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + if (spellEffect->Effect == SPELL_EFFECT_ENERGIZE) { - if (m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + if(spellEffect->EffectMiscValue < 0 || spellEffect->EffectMiscValue >= MAX_POWERS) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; continue; } - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + Powers power = Powers(spellEffect->EffectMiscValue); if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; @@ -6601,10 +6858,10 @@ SpellCastResult Spell::CheckItems() } // check spell focus object - if (m_spellInfo->RequiresSpellFocus) + if(uint32 spellFocus = m_spellInfo->GetRequiresSpellFocus()) { GameObject* ok = NULL; - MaNGOS::GameObjectFocusCheck go_check(m_caster, m_spellInfo->RequiresSpellFocus); + MaNGOS::GameObjectFocusCheck go_check(m_caster, spellFocus); MaNGOS::GameObjectSearcher checker(ok, go_check); Cell::VisitGridObjects(m_caster, checker, m_caster->GetMap()->GetVisibilityDistance()); @@ -6619,89 +6876,100 @@ SpellCastResult Spell::CheckItems() { if (!p_caster->CanNoReagentCast(m_spellInfo)) { - for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i) + SpellReagentsEntry const* spellReagents = m_spellInfo->GetSpellReagents(); + if(spellReagents) { - if (m_spellInfo->Reagent[i] <= 0) - continue; - - uint32 itemid = m_spellInfo->Reagent[i]; - uint32 itemcount = m_spellInfo->ReagentCount[i]; - - // if CastItem is also spell reagent - if (m_CastItem && m_CastItem->GetEntry() == itemid) + for(uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i) { - ItemPrototype const* proto = m_CastItem->GetProto(); - if (!proto) - return SPELL_FAILED_REAGENTS; - for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) + if(spellReagents->Reagent[i] <= 0) + continue; + + uint32 itemid = spellReagents->Reagent[i]; + uint32 itemcount = spellReagents->ReagentCount[i]; + + // if CastItem is also spell reagent + if (m_CastItem && m_CastItem->GetEntry() == itemid) { - // CastItem will be used up and does not count as reagent - int32 charges = m_CastItem->GetSpellCharges(s); - if (proto->Spells[s].SpellCharges < 0 && !(proto->ExtraFlags & ITEM_EXTRA_NON_CONSUMABLE) && abs(charges) < 2) + ItemPrototype const *proto = m_CastItem->GetProto(); + if (!proto) + return SPELL_FAILED_REAGENTS; + for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s) { - ++itemcount; - break; + // CastItem will be used up and does not count as reagent + int32 charges = m_CastItem->GetSpellCharges(s); + if (proto->Spells[s].SpellCharges < 0 && !(proto->ExtraFlags & ITEM_EXTRA_NON_CONSUMABLE) && abs(charges) < 2) + { + ++itemcount; + break; + } } } - } - if (!p_caster->HasItemCount(itemid, itemcount)) - return SPELL_FAILED_REAGENTS; + if (!p_caster->HasItemCount(itemid, itemcount)) + return SPELL_FAILED_REAGENTS; + } } } // check totem-item requirements (items presence in inventory) - uint32 totems = MAX_SPELL_TOTEMS; - for (int i = 0; i < MAX_SPELL_TOTEMS ; ++i) + SpellTotemsEntry const* spellTotems = m_spellInfo->GetSpellTotems(); + if(spellTotems) { - if (m_spellInfo->Totem[i] != 0) + uint32 totems = MAX_SPELL_TOTEMS; + for(int i = 0; i < MAX_SPELL_TOTEMS ; ++i) { - if (p_caster->HasItemCount(m_spellInfo->Totem[i], 1)) + if (spellTotems->Totem[i] != 0) { + if (p_caster->HasItemCount(spellTotems->Totem[i], 1)) + { + totems -= 1; + continue; + } + } + else totems -= 1; - continue; - } } - else - totems -= 1; - } - if (totems != 0) - return SPELL_FAILED_TOTEMS; + if (totems != 0) + return SPELL_FAILED_TOTEMS; - // Check items for TotemCategory (items presence in inventory) - uint32 TotemCategory = MAX_SPELL_TOTEM_CATEGORIES; - for (int i = 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i) - { - if (m_spellInfo->TotemCategory[i] != 0) + // Check items for TotemCategory (items presence in inventory) + uint32 TotemCategory = MAX_SPELL_TOTEM_CATEGORIES; + for(int i= 0; i < MAX_SPELL_TOTEM_CATEGORIES; ++i) { - if (p_caster->HasItemTotemCategory(m_spellInfo->TotemCategory[i])) + if (spellTotems->TotemCategory[i] != 0) { - TotemCategory -= 1; - continue; + if (p_caster->HasItemTotemCategory(spellTotems->TotemCategory[i])) + { + TotemCategory -= 1; + continue; + } } + else + TotemCategory -= 1; } - else - TotemCategory -= 1; - } - if (TotemCategory != 0) - return SPELL_FAILED_TOTEM_CATEGORY; + if (TotemCategory != 0) + return SPELL_FAILED_TOTEM_CATEGORY; + } } // special checks for spell effects for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { - switch (m_spellInfo->Effect[i]) + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + switch (spellEffect->Effect) { case SPELL_EFFECT_CREATE_ITEM: { - if (!m_IsTriggeredSpell && m_spellInfo->EffectItemType[i]) + if (!m_IsTriggeredSpell && spellEffect->EffectItemType) { // Conjure Mana Gem (skip same or low level ranks for later recharge) - if (i == EFFECT_INDEX_0 && m_spellInfo->Effect[EFFECT_INDEX_1] == SPELL_EFFECT_DUMMY) + if (i == EFFECT_INDEX_0 && m_spellInfo->GetSpellEffectIdByIndex(EFFECT_INDEX_1) == SPELL_EFFECT_DUMMY) { - if (ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(m_spellInfo->EffectItemType[i])) + if (ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(spellEffect->EffectItemType)) { if (Item* item = p_caster->GetItemByLimitedCategory(itemProto->ItemLimitCategory)) { @@ -6718,10 +6986,10 @@ SpellCastResult Spell::CheckItems() } ItemPosCountVec dest; - InventoryResult msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1); - if (msg != EQUIP_ERR_OK) + InventoryResult msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffect->EffectItemType, 1 ); + if (msg != EQUIP_ERR_OK ) { - p_caster->SendEquipError(msg, NULL, NULL, m_spellInfo->EffectItemType[i]); + p_caster->SendEquipError( msg, NULL, NULL, spellEffect->EffectItemType ); return SPELL_FAILED_DONT_REPORT; } } @@ -6729,7 +6997,7 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_RESTORE_ITEM_CHARGES: { - if (Item* item = p_caster->GetItemByEntry(m_spellInfo->EffectItemType[i])) + if (Item* item = p_caster->GetItemByEntry(spellEffect->EffectItemType)) if (item->HasMaxCharges()) return SPELL_FAILED_ITEM_AT_MAX_CHARGES; @@ -6742,13 +7010,13 @@ SpellCastResult Spell::CheckItems() if (!targetItem) return SPELL_FAILED_ITEM_NOT_FOUND; - if (targetItem->GetProto()->ItemLevel < m_spellInfo->baseLevel) + if( targetItem->GetProto()->ItemLevel < m_spellInfo->GetBaseLevel() ) return SPELL_FAILED_LOWLEVEL; // Check if we can store a new scroll, enchanting vellum has implicit SPELL_EFFECT_CREATE_ITEM - if (isVellumTarget && m_spellInfo->EffectItemType[i]) + if (isVellumTarget && spellEffect->EffectItemType) { ItemPosCountVec dest; - InventoryResult msg = p_caster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->EffectItemType[i], 1); + InventoryResult msg = p_caster->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellEffect->EffectItemType, 1 ); if (msg != EQUIP_ERR_OK) { p_caster->SendEquipError(msg, NULL, NULL); @@ -6758,9 +7026,9 @@ SpellCastResult Spell::CheckItems() // Not allow enchant in trade slot for some enchant type if (targetItem->GetOwner() != m_caster) { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) + uint32 enchant_id = spellEffect->EffectMiscValue; + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) return SPELL_FAILED_ERROR; if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) return SPELL_FAILED_NOT_TRADEABLE; @@ -6778,9 +7046,9 @@ SpellCastResult Spell::CheckItems() // Not allow enchant in trade slot for some enchant type if (item->GetOwner() != m_caster) { - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) + uint32 enchant_id = spellEffect->EffectMiscValue; + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); + if(!pEnchant) return SPELL_FAILED_ERROR; if (pEnchant->slot & ENCHANTMENT_CAN_SOULBOUND) return SPELL_FAILED_NOT_TRADEABLE; @@ -6877,46 +7145,6 @@ SpellCastResult Spell::CheckItems() if (!((Player*)m_caster)->HasItemCount(ammo, 1)) return SPELL_FAILED_NO_AMMO; }; break; - case ITEM_SUBCLASS_WEAPON_GUN: - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - { - uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID); - if (!ammo) - { - // Requires No Ammo - if (m_caster->GetDummyAura(46699)) - break; // skip other checks - - return SPELL_FAILED_NO_AMMO; - } - - ItemPrototype const* ammoProto = ObjectMgr::GetItemPrototype(ammo); - if (!ammoProto) - return SPELL_FAILED_NO_AMMO; - - if (ammoProto->Class != ITEM_CLASS_PROJECTILE) - return SPELL_FAILED_NO_AMMO; - - // check ammo ws. weapon compatibility - switch (pItem->GetProto()->SubClass) - { - case ITEM_SUBCLASS_WEAPON_BOW: - case ITEM_SUBCLASS_WEAPON_CROSSBOW: - if (ammoProto->SubClass != ITEM_SUBCLASS_ARROW) - return SPELL_FAILED_NO_AMMO; - break; - case ITEM_SUBCLASS_WEAPON_GUN: - if (ammoProto->SubClass != ITEM_SUBCLASS_BULLET) - return SPELL_FAILED_NO_AMMO; - break; - default: - return SPELL_FAILED_NO_AMMO; - } - - if (!((Player*)m_caster)->HasItemCount(ammo, 1)) - return SPELL_FAILED_NO_AMMO; - }; break; case ITEM_SUBCLASS_WEAPON_WAND: break; default: @@ -6943,7 +7171,7 @@ void Spell::Delayed() return; // spells not loosing casting time ( slam, dynamites, bombs.. ) - if (!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE)) + if(!(m_spellInfo->GetInterruptFlags() & SPELL_INTERRUPT_FLAG_DAMAGE)) return; // check pushback reduce @@ -7045,10 +7273,10 @@ void Spell::UpdatePointers() bool Spell::CheckTargetCreatureType(Unit* target) const { - uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; + uint32 spellCreatureTargetMask = m_spellInfo->GetTargetCreatureType(); // Curse of Doom: not find another way to fix spell target check :/ - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179) + if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_WARLOCK && m_spellInfo->GetCategory() == 1179) { // not allow cast at player if (target->GetTypeId() == TYPEID_PLAYER) @@ -7084,18 +7312,26 @@ CurrentSpellTypes Spell::GetCurrentContainer() bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) { + SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(eff); + if(!spellEffect) + return false; + // Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets) - if (m_spellInfo->EffectImplicitTargetA[eff] != TARGET_SELF) + if(spellEffect->EffectImplicitTargetA != TARGET_SELF ) { if (!CheckTargetCreatureType(target)) return false; } // Check Aura spell req (need for AoE spells) - if (m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell)) - return false; - if (m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell)) - return false; + SpellAuraRestrictionsEntry const* auraRestrictions = m_spellInfo->GetSpellAuraRestrictions(); + if(auraRestrictions) + { + if(auraRestrictions->targetAuraSpell && !target->HasAura(auraRestrictions->targetAuraSpell)) + return false; + if (auraRestrictions->excludeTargetAuraSpell && target->HasAura(auraRestrictions->excludeTargetAuraSpell)) + return false; + } // Check targets for not_selectable unit flag and remove // A player can cast spells on his pet (or other controlled unit) though in any state @@ -7108,13 +7344,13 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) // unselectable targets skipped in all cases except TARGET_SCRIPT targeting // in case TARGET_SCRIPT target selected by server always and can't be cheated if ((!m_IsTriggeredSpell || target != m_targets.getUnitTarget()) && - target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_SCRIPT && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_SCRIPT && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_AREAEFFECT_INSTANT && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_AREAEFFECT_INSTANT && - m_spellInfo->EffectImplicitTargetA[eff] != TARGET_AREAEFFECT_CUSTOM && - m_spellInfo->EffectImplicitTargetB[eff] != TARGET_AREAEFFECT_CUSTOM) + target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && + spellEffect->EffectImplicitTargetA != TARGET_SCRIPT && + spellEffect->EffectImplicitTargetB != TARGET_SCRIPT && + spellEffect->EffectImplicitTargetA != TARGET_AREAEFFECT_INSTANT && + spellEffect->EffectImplicitTargetB != TARGET_AREAEFFECT_INSTANT && + spellEffect->EffectImplicitTargetA != TARGET_AREAEFFECT_CUSTOM && + spellEffect->EffectImplicitTargetB != TARGET_AREAEFFECT_CUSTOM ) return false; } @@ -7129,7 +7365,7 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) } // Check targets for LOS visibility (except spells without range limitations ) - switch (m_spellInfo->Effect[eff]) + switch(spellEffect->Effect) { case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere break; @@ -7186,8 +7422,8 @@ bool Spell::IsNeedSendToClient() const bool Spell::IsTriggeredSpellWithRedundentData() const { return m_triggeredByAuraSpell || m_triggeredBySpellInfo || - // possible not need after above check? - m_IsTriggeredSpell && (m_spellInfo->manaCost || m_spellInfo->ManaCostPercentage); + // possible not need after above check? + m_IsTriggeredSpell && (m_spellInfo->GetManaCost() || m_spellInfo->GetManaCostPercentage()); } bool Spell::HaveTargetsForEffect(SpellEffectIndex effect) const @@ -7355,7 +7591,7 @@ SpellCastResult Spell::CanOpenLock(SpellEffectIndex effIndex, uint32 lockId, Ski reqKey = true; // wrong locktype, skip - if (uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) + if(uint32(m_spellInfo->GetEffectMiscValue(effIndex)) != lockInfo->Index[j]) continue; skillId = SkillByLockType(LockType(lockInfo->Index[j])); @@ -7544,7 +7780,11 @@ void Spell::SelectMountByAreaAndSkill(Unit* target, SpellEntry const* parentSpel SpellEntry const* spellInfo = sSpellStore.LookupEntry(iter->first); for (int i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) + SpellEffectEntry const* spellEffect = spellInfo->GetSpellEffect(SpellEffectIndex(i)); + if(!spellEffect) + continue; + + if(spellEffect->EffectApplyAuraName == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) { int32 mountSpeed = spellInfo->CalculateSimpleValue(SpellEffectIndex(i)); @@ -7592,7 +7832,7 @@ bool Spell::HasGlobalCooldown() void Spell::TriggerGlobalCooldown() { - int32 gcd = m_spellInfo->StartRecoveryTime; + int32 gcd = m_spellInfo->GetStartRecoveryTime(); if (!gcd) return; @@ -7623,7 +7863,7 @@ void Spell::TriggerGlobalCooldown() void Spell::CancelGlobalCooldown() { - if (!m_spellInfo->StartRecoveryTime) + if (!m_spellInfo->GetStartRecoveryTime()) return; // cancel global cooldown when interrupting current cast diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 95d2369b4..657f0b5e1 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ -#define REVISION_NR "0162" +#define REVISION_NR "0163" #endif // __REVISION_NR_H__