diff options
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 627 |
1 files changed, 314 insertions, 313 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8583d055123..5c247d86fa3 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -509,18 +509,20 @@ void SpellCastTargets::OutDebug() const SpellValue::SpellValue(SpellInfo const* proto) { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - EffectBasePoints[i] = proto->Effects[i].BasePoints; + // todo 6.x + //for (uint32 i = 0; i < proto->Effects.size(); ++i) + // EffectBasePoints[i] = proto->Effects[i].BasePoints; MaxAffectedTargets = proto->MaxAffectedTargets; RadiusMod = 1.0f; AuraStackAmount = 1; } Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) : -m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)), -m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster) -, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) +m_spellInfo(info), m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster), +m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) { + difficultyEffects = info->GetEffectsForDifficulty(caster->GetMap()->GetDifficulty()); + m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; m_selfContainer = NULL; @@ -764,36 +766,37 @@ void Spell::SelectSpellTargets() SelectExplicitTargets(); uint32 processedAreaEffectsMask = 0; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + + for (SpellEffectInfo const* effect : GetEffects()) { // 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->Effects[i].IsEffect()) + if (!effect->IsEffect()) continue; // set expected type of implicit targets to be sent to client - uint32 implicitTargetMask = GetTargetFlagMask(m_spellInfo->Effects[i].TargetA.GetObjectType()) | GetTargetFlagMask(m_spellInfo->Effects[i].TargetB.GetObjectType()); + uint32 implicitTargetMask = GetTargetFlagMask(effect->TargetA.GetObjectType()) | GetTargetFlagMask(effect->TargetB.GetObjectType()); if (implicitTargetMask & TARGET_FLAG_UNIT) m_targets.SetTargetFlag(TARGET_FLAG_UNIT); if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM)) m_targets.SetTargetFlag(TARGET_FLAG_GAMEOBJECT); - SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetA, processedAreaEffectsMask); - SelectEffectImplicitTargets(SpellEffIndex(i), m_spellInfo->Effects[i].TargetB, processedAreaEffectsMask); + SelectEffectImplicitTargets(SpellEffIndex(effect->EffectIndex), effect->TargetA, processedAreaEffectsMask); + SelectEffectImplicitTargets(SpellEffIndex(effect->EffectIndex), effect->TargetB, processedAreaEffectsMask); // Select targets of effect based on effect type // those are used when no valid target could be added for spell effect based on spell target type // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL) // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON) // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS) - SelectEffectTypeImplicitTargets(i); + SelectEffectTypeImplicitTargets(effect->EffectIndex); if (m_targets.HasDst()) - AddDestTarget(*m_targets.GetDst(), i); + AddDestTarget(*m_targets.GetDst(), effect->EffectIndex); if (m_spellInfo->IsChanneled()) { - uint8 mask = (1 << i); + uint32 mask = (1 << effect->EffectIndex); for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->effectMask & mask) @@ -864,17 +867,19 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar if (effectMask & processedEffectMask) return; // choose which targets we can select at once - for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - SpellEffectInfo const* effects = GetSpellInfo()->Effects; - if (effects[j].IsEffect() && - effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() && - effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() && - effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions && - effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) && - CheckScriptEffectImplicitTargets(effIndex, j)) + //for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j) + if (effect->EffectIndex <= uint32(effIndex)) + continue; + if (effect->IsEffect() && + effect->TargetA.GetTarget() == effect->TargetA.GetTarget() && + effect->TargetB.GetTarget() == effect->TargetB.GetTarget() && + effect->ImplicitTargetConditions == effect->ImplicitTargetConditions && + effect->CalcRadius(m_caster) == effect->CalcRadius(m_caster) && + CheckScriptEffectImplicitTargets(effIndex, effect->EffectIndex)) { - effectMask |= 1 << j; + effectMask |= 1 << effect->EffectIndex; } } processedEffectMask |= effectMask; @@ -1009,6 +1014,10 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar return; } + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + float range = 0.0f; switch (targetType.GetCheckType()) { @@ -1030,7 +1039,7 @@ void Spell::SelectImplicitNearbyTargets(SpellEffIndex effIndex, SpellImplicitTar break; } - ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + ConditionList* condList = effect->ImplicitTargetConditions; // handle emergency case - try to use other provided targets if no conditions provided if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty())) @@ -1116,9 +1125,12 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge std::list<WorldObject*> targets; SpellTargetObjectTypes objectType = targetType.GetObjectType(); SpellTargetCheckTypes selectionType = targetType.GetCheckType(); - ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + ConditionList* condList = effect->ImplicitTargetConditions; float coneAngle = float(M_PI) / 2; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; + float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList)) { @@ -1199,8 +1211,11 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge } std::list<WorldObject*> targets; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; - SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod; + SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect->ImplicitTargetConditions); CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -1236,7 +1251,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, effIndex)) { /// @todo fix this check - if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND)) + if (HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || HasEffect(SPELL_EFFECT_BIND)) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); else if (st->target_mapId == m_caster->GetMapId()) dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation); @@ -1284,23 +1299,26 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici } default: { - float dist; - float angle = targetType.CalcDirectionAngle(); - float objSize = m_caster->GetObjectSize(); - if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON) - dist = PET_FOLLOW_DIST; - else - dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float dist; + float angle = targetType.CalcDirectionAngle(); + float objSize = m_caster->GetObjectSize(); + if (targetType.GetTarget() == TARGET_DEST_CASTER_SUMMON) + dist = PET_FOLLOW_DIST; + else + dist = effect->CalcRadius(m_caster); - if (dist < objSize) - dist = objSize; - else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM) - dist = objSize + (dist - objSize) * float(rand_norm()); + if (dist < objSize) + dist = objSize; + else if (targetType.GetTarget() == TARGET_DEST_CASTER_RANDOM) + dist = objSize + (dist - objSize) * float(rand_norm()); - Position pos = dest._position; - m_caster->MovePositionToFirstCollision(pos, dist, angle); + Position pos = dest._position; + m_caster->MovePositionToFirstCollision(pos, dist, angle); - dest.Relocate(pos); + dest.Relocate(pos); + } break; } } @@ -1323,18 +1341,21 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici break; default: { - float angle = targetType.CalcDirectionAngle(); - float objSize = target->GetObjectSize(); - float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); - if (dist < objSize) - dist = objSize; - else if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM) - dist = objSize + (dist - objSize) * float(rand_norm()); - - Position pos = dest._position; - target->MovePositionToFirstCollision(pos, dist, angle); - - dest.Relocate(pos); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float angle = targetType.CalcDirectionAngle(); + float objSize = target->GetObjectSize(); + float dist = effect->CalcRadius(m_caster); + if (dist < objSize) + dist = objSize; + else if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM) + dist = objSize + (dist - objSize) * float(rand_norm()); + + Position pos = dest._position; + target->MovePositionToFirstCollision(pos, dist, angle); + + dest.Relocate(pos); + } break; } } @@ -1365,15 +1386,18 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT return; default: { - float angle = targetType.CalcDirectionAngle(); - float dist = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); - if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM) - dist *= float(rand_norm()); + if (SpellEffectInfo const* effect = GetEffect(effIndex)) + { + float angle = targetType.CalcDirectionAngle(); + float dist = effect->CalcRadius(m_caster); + if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM) + dist *= float(rand_norm()); - Position pos = dest._position; - m_caster->MovePositionToFirstCollision(pos, dist, angle); + Position pos = dest._position; + m_caster->MovePositionToFirstCollision(pos, dist, angle); - dest.Relocate(pos); + dest.Relocate(pos); + } break; } } @@ -1451,21 +1475,25 @@ void Spell::SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImpli void Spell::SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask) { - uint32 maxTargets = m_spellInfo->Effects[effIndex].ChainTargets; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + + uint32 maxTargets = effect->ChainTargets; if (Player* modOwner = m_caster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this); if (maxTargets > 1) { // mark damage multipliers as used - for (uint32 k = effIndex; k < MAX_SPELL_EFFECTS; ++k) - if (effMask & (1 << k)) - m_damageMultipliers[k] = 1.0f; + for (SpellEffectInfo const* eff : GetEffects()) + if (effMask & (1 << eff->EffectIndex)) + m_damageMultipliers[eff->EffectIndex] = 1.0f; m_applyMultiplierMask |= effMask; std::list<WorldObject*> targets; SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType() - , m_spellInfo->Effects[effIndex].ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); + , effect->ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY); // Chain primary target is added earlier CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType); @@ -1644,11 +1672,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) veh->SetLastShootPos(*m_targets.GetDstPos()); } -void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) +void Spell::SelectEffectTypeImplicitTargets(uint32 effIndex) { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER /// @todo this is a workaround - target shouldn't be stored in target map for those spells - switch (m_spellInfo->Effects[effIndex].Effect) + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return; + switch (effect->Effect) { case SPELL_EFFECT_SUMMON_RAF_FRIEND: case SPELL_EFFECT_SUMMON_PLAYER: @@ -1667,17 +1698,17 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) } // select spell implicit targets based on effect type - if (!m_spellInfo->Effects[effIndex].GetImplicitTargetType()) + if (!effect->GetImplicitTargetType()) return; - uint32 targetMask = m_spellInfo->Effects[effIndex].GetMissingTargetMask(); + uint32 targetMask = effect->GetMissingTargetMask(); if (!targetMask) return; WorldObject* target = NULL; - switch (m_spellInfo->Effects[effIndex].GetImplicitTargetType()) + switch (effect->GetImplicitTargetType()) { // add explicit object target or self to the target map case EFFECT_IMPLICIT_TARGET_EXPLICIT: @@ -2012,9 +2043,9 @@ void Spell::CleanupTargetList() void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (!m_spellInfo->Effects[effIndex].IsEffect() || !CheckEffectTarget(target, effIndex, losPosition)) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (!effect->IsEffect() || !CheckEffectTarget(target, effect->EffectIndex, losPosition)) + effectMask &= ~(1 << effect->EffectIndex); // no effects left if (!effectMask) @@ -2025,9 +2056,9 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= return; // Check for effect immune skip if immuned - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (target->IsImmunedToSpellEffect(m_spellInfo, effIndex)) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (target->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex)) + effectMask &= ~(1 << effect->EffectIndex); ObjectGuid targetGUID = target->GetGUID(); @@ -2120,19 +2151,19 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= void Spell::AddGOTarget(GameObject* go, uint32 effectMask) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetEffects()) { - if (!m_spellInfo->Effects[effIndex].IsEffect()) - effectMask &= ~(1 << effIndex); + if (!effect->IsEffect()) + effectMask &= ~(1 << effect->EffectIndex); else { - switch (m_spellInfo->Effects[effIndex].Effect) + switch (effect->Effect) { case SPELL_EFFECT_GAMEOBJECT_DAMAGE: case SPELL_EFFECT_GAMEOBJECT_REPAIR: case SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE: if (go->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING) - effectMask &= ~(1 << effIndex); + effectMask &= ~(1 << effect->EffectIndex); break; default: break; @@ -2187,9 +2218,9 @@ void Spell::AddGOTarget(GameObject* go, uint32 effectMask) void Spell::AddItemTarget(Item* item, uint32 effectMask) { - for (uint32 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - if (!m_spellInfo->Effects[effIndex].IsEffect()) - effectMask &= ~(1 << effIndex); + for (SpellEffectInfo const* effect : GetEffects()) + if (!effect->IsEffect()) + effectMask &= ~(1 << effect->EffectIndex); // no effects left if (!effectMask) @@ -2234,10 +2265,10 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { uint8 farMask = 0; // create far target mask - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].IsFarUnitTargetEffect()) - if ((1 << i) & mask) - farMask |= (1 << i); + for (SpellEffectInfo const* effect : GetEffects()) + if (effect->IsFarUnitTargetEffect()) + if ((1 << effect->EffectIndex) & mask) + farMask |= (1 << effect->EffectIndex); if (!farMask) return; @@ -2248,9 +2279,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // do far effects on the unit // can't use default call because of threading, do stuff as fast as possible - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (farMask & (1 << i)) - HandleEffects(unit, NULL, NULL, i, SPELL_EFFECT_HANDLE_HIT_TARGET); + for(SpellEffectInfo const* effect : GetEffects()) + if (farMask & (1 << effect->EffectIndex)) + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); return; } @@ -2433,7 +2464,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) } } - if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) + if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || HasEffect(SPELL_EFFECT_DISPEL))) { m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_NO_INITIAL_AGGRO)); @@ -2474,10 +2505,10 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // disable effects to which unit is immune SpellMissInfo returnVal = SPELL_MISS_IMMUNE; - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - if (unit->IsImmunedToSpellEffect(m_spellInfo, effectNumber)) - effectMask &= ~(1 << effectNumber); + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex)) + if (unit->IsImmunedToSpellEffect(m_spellInfo, effect->EffectIndex)) + effectMask &= ~(1 << effect->EffectIndex); if (!effectMask) return returnVal; @@ -2535,9 +2566,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } uint8 aura_effmask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) - aura_effmask |= 1 << i; + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex) && effect->IsUnitOwnedAuraEffect()) + aura_effmask |= 1 << effect->EffectIndex; // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add m_diminishGroup = GetDiminishingReturnsGroupForSpell(m_spellInfo, m_triggeredByAuraSpell != nullptr); @@ -2557,18 +2588,21 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // Select rank for aura with level requirements only in specific cases // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target SpellInfo const* aurSpellInfo = m_spellInfo; - int32 basePoints[3]; + int32 basePoints[MAX_SPELL_EFFECTS]; if (scaleAura) { aurSpellInfo = m_spellInfo->GetAuraRankForLevel(unitTarget->getLevel()); ASSERT(aurSpellInfo); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : aurSpellInfo->GetEffectsForDifficulty(0)) { - basePoints[i] = aurSpellInfo->Effects[i].BasePoints; - if (m_spellInfo->Effects[i].Effect != aurSpellInfo->Effects[i].Effect) + basePoints[effect->EffectIndex] = effect->BasePoints; + if (SpellEffectInfo const* myEffect = GetEffect(effect->EffectIndex)) { - aurSpellInfo = m_spellInfo; - break; + if (myEffect->Effect != effect->Effect) + { + aurSpellInfo = m_spellInfo; + break; + } } } } @@ -2599,8 +2633,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { m_spellAura->Remove(); bool found = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].Effect != SPELL_EFFECT_APPLY_AURA) + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex) && effect->Effect != SPELL_EFFECT_APPLY_AURA) found = true; if (!found) return SPELL_MISS_IMMUNE; @@ -2624,8 +2658,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA { int32 origDuration = duration; duration = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (AuraEffect const* eff = m_spellAura->GetEffect(i)) + for (SpellEffectInfo const* effect : GetEffects()) + if (AuraEffect const* eff = m_spellAura->GetEffect(effect->EffectIndex)) if (int32 period = eff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED duration = std::max(std::max(origDuration / period, 1) * period, duration); @@ -2646,9 +2680,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } } - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(unit, NULL, NULL, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex)) + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); return SPELL_MISS_NONE; } @@ -2742,9 +2776,9 @@ void Spell::DoAllEffectOnTarget(GOTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(); - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(NULL, NULL, go, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex)) + HandleEffects(NULL, NULL, go, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); CallScriptOnHitHandlers(); CallScriptAfterHitHandlers(); @@ -2759,9 +2793,9 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo* target) PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(); - for (uint32 effectNumber = 0; effectNumber < MAX_SPELL_EFFECTS; ++effectNumber) - if (effectMask & (1 << effectNumber)) - HandleEffects(NULL, target->item, NULL, effectNumber, SPELL_EFFECT_HANDLE_HIT_TARGET); + for (SpellEffectInfo const* effect : GetEffects()) + if (effectMask & (1 << effect->EffectIndex)) + HandleEffects(NULL, target->item, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT_TARGET); CallScriptOnHitHandlers(); @@ -2776,9 +2810,9 @@ bool Spell::UpdateChanneledTargetList() uint8 channelTargetEffectMask = m_channelTargetEffectMask; uint8 channelAuraMask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) - channelAuraMask |= 1<<i; + for (SpellEffectInfo const* effect : GetEffects()) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) + channelAuraMask |= 1 << effect->EffectIndex; channelAuraMask &= channelTargetEffectMask; @@ -2843,15 +2877,15 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // Fill aura scaling information if (m_caster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING)) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) { // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive - if (m_spellInfo->IsPositiveEffect(i)) + if (m_spellInfo->IsPositiveEffect(effect->EffectIndex)) { - m_auraScaleMask |= (1 << i); - if (m_spellValue->EffectBasePoints[i] != m_spellInfo->Effects[i].BasePoints) + m_auraScaleMask |= (1 << effect->EffectIndex); + if (m_spellValue->EffectBasePoints[effect->EffectIndex] != effect->BasePoints) { m_auraScaleMask = 0; break; @@ -2966,8 +3000,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth()) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_spellInfo->Effects[i].GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) + for (SpellEffectInfo const* effect : GetEffects()) + if (effect->GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK); break; @@ -3296,10 +3330,6 @@ void Spell::handle_immediate() // Remove used for cast item if need (it can be already NULL after TakeReagents call TakeCastItem(); - // handle ammo consumption for thrown weapons - if (m_spellInfo->IsRangedWeaponSpell() && m_spellInfo->IsChanneled()) - TakeAmmo(); - if (m_spellState != SPELL_STATE_CASTING) finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell) } @@ -3391,14 +3421,14 @@ void Spell::_handle_immediate_phase() PrepareScriptHitHandlers(); // handle effects with SPELL_EFFECT_HANDLE_HIT mode - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { // don't do anything for empty effect - if (!m_spellInfo->Effects[j].IsEffect()) + if (!effect->IsEffect()) continue; // call effect handlers to handle destination hit - HandleEffects(NULL, NULL, NULL, j, SPELL_EFFECT_HANDLE_HIT); + HandleEffects(NULL, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_HIT); } // process items @@ -3436,7 +3466,7 @@ void Spell::_handle_finish_phase() HandleHolyPower(m_caster->m_movedPlayer); } - if (m_caster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) + if (m_caster->m_extraAttacks && HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) { if (Unit* victim = ObjectAccessor::FindUnit(m_targets.GetOrigUnitTargetGUID())) m_caster->HandleProcExtraAttackFor(victim); @@ -3494,9 +3524,10 @@ void Spell::update(uint32 difftime) // check if the player caster has moved before the spell finished // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect + SpellEffectInfo const* effect = GetEffect(EFFECT_0); if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) && m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && - (m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && + ((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // don't cancel for melee, autorepeat, triggered and instant spells @@ -3724,9 +3755,9 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas case SPELL_FAILED_TOO_MANY_OF_ITEM: { uint32 item = 0; - for (int8 eff = 0; eff < MAX_SPELL_EFFECTS; eff++) - if (spellInfo->Effects[eff].ItemType) - item = spellInfo->Effects[eff].ItemType; + for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(caster->GetMap()->GetDifficulty())) + if (effect->ItemType) + item = effect->ItemType; ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item); if (proto && proto->ItemLimitCategory) data << uint32(proto->ItemLimitCategory); @@ -3897,7 +3928,7 @@ void Spell::SendSpellGo() castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list } - if (m_spellInfo->HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) + if (HasEffect(SPELL_EFFECT_ACTIVATE_RUNE)) castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list if (m_targets.HasTraj()) @@ -4052,9 +4083,9 @@ void Spell::SendLogExecute() data << uint32(m_spellInfo->Id); uint8 effCount = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_effectExecuteData[i]) + if (m_effectExecuteData[effect->EffectIndex]) ++effCount; } @@ -4062,17 +4093,17 @@ void Spell::SendLogExecute() return; data << uint32(effCount); - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (!m_effectExecuteData[i]) + if (!m_effectExecuteData[effect->EffectIndex]) continue; - data << uint32(m_spellInfo->Effects[i].Effect); // spell effect + data << uint32(effect->Effect); // spell effect - data.append(*m_effectExecuteData[i]); + data.append(*m_effectExecuteData[effect->EffectIndex]); - delete m_effectExecuteData[i]; - m_effectExecuteData[i] = NULL; + delete m_effectExecuteData[effect->EffectIndex]; + m_effectExecuteData[effect->EffectIndex] = NULL; } m_caster->SendMessageToSet(&data, true); } @@ -4407,36 +4438,6 @@ void Spell::TakePower() m_caster->ModifyPower(powerType, -irand(0, m_powerCost/4)); } -void Spell::TakeAmmo() -{ - if (m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER) - { - Item* pItem = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK); - - // wands don't have ammo - if (!pItem || pItem->IsBroken() || pItem->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND) - return; - - if ((pItem->GetTemplate()->InventoryType == INVTYPE_THROWN || - pItem->GetTemplate()->InventoryType == INVTYPE_RANGED || - pItem->GetTemplate()->InventoryType == INVTYPE_RANGEDRIGHT) - && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE))) - { - if (pItem->GetMaxStackCount() == 1) - { - // decrease durability for non-stackable throw weapon - m_caster->ToPlayer()->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED); - } - else - { - // decrease items amount for stackable throw weapon - uint32 count = 1; - m_caster->ToPlayer()->DestroyItemCount(pItem, count, true); - } - } - } -} - SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { if (m_spellInfo->PowerType != POWER_RUNES || !runeCostID) @@ -4693,9 +4694,15 @@ void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGOT gameObjTarget = pGOTarget; destTarget = &m_destTargets[i]._position; - uint8 eff = m_spellInfo->Effects[i].Effect; + SpellEffectInfo const* effect = GetEffect(i); + if (!effect) + { + TC_LOG_ERROR("spells", "Spell: %u HandleEffects at EffectIndex: %u missing effect", m_spellInfo->Id, i); + return; + } + uint8 eff = effect->Effect; - TC_LOG_DEBUG("spells", "Spell: %u Effect : %u", m_spellInfo->Id, eff); + TC_LOG_DEBUG("spells", "Spell: %u Effect: %u", m_spellInfo->Id, eff); damage = CalculateDamage(i, unitTarget); @@ -4816,9 +4823,9 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_CASTER_AURASTATE; // Note: spell 62473 requres casterAuraSpell = triggering spell - if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, m_caster))) + if (m_spellInfo->CasterAuraSpell && !m_caster->HasAura(m_spellInfo->CasterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; - if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, m_caster))) + if (m_spellInfo->ExcludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->ExcludeCasterAuraSpell)) return SPELL_FAILED_CASTER_AURASTATE; if (reqCombat && m_caster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat()) @@ -4831,7 +4838,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->isMoving() && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo)) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement - if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || m_spellInfo->Effects[0].Effect != SPELL_EFFECT_STUCK) && + SpellEffectInfo const* effect = GetEffect(EFFECT_0); + if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) && (IsAutoRepeat() || (m_spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED) != 0)) return SPELL_FAILED_MOVING; } @@ -4916,9 +4924,9 @@ SpellCastResult Spell::CheckCast(bool strict) } // check pet presence - for (int j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[j].TargetA.GetTarget() == TARGET_UNIT_PET) + if (effect->TargetA.GetTarget() == TARGET_UNIT_PET) { if (!m_caster->GetGuardianPet()) { @@ -5009,10 +5017,10 @@ SpellCastResult Spell::CheckCast(bool strict) if (castResult != SPELL_CAST_OK) return castResult; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { // for effects of spells that have only one target - switch (m_spellInfo->Effects[i].Effect) + switch (effect->Effect) { case SPELL_EFFECT_DUMMY: { @@ -5039,7 +5047,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetTypeId() != TYPEID_PLAYER) return SPELL_FAILED_BAD_TARGETS; - if (m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_PET) + if (effect->TargetA.GetTarget() != TARGET_UNIT_PET) break; Pet* pet = m_caster->ToPlayer()->GetPet(); @@ -5047,7 +5055,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet) return SPELL_FAILED_NO_PET; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[i].TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5078,7 +5086,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (!pet || pet->GetOwner() != m_caster) return SPELL_FAILED_BAD_TARGETS; - SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[i].TriggerSpell); + SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effect->TriggerSpell); if (!learn_spellproto) return SPELL_FAILED_NOT_KNOWN; @@ -5090,7 +5098,7 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_APPLY_GLYPH: { - uint32 glyphId = m_spellInfo->Effects[i].MiscValue; + uint32 glyphId = effect->MiscValue; if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId)) if (m_caster->HasAura(gp->SpellID)) return SPELL_FAILED_UNIQUE_GLYPH; @@ -5127,7 +5135,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 && target->getPowerType() != Powers(m_spellInfo->Effects[i].MiscValue)) + if (target != m_caster && target->getPowerType() != Powers(effect->MiscValue)) return SPELL_FAILED_BAD_TARGETS; break; } @@ -5200,13 +5208,13 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_OPEN_LOCK: { - if (m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET && - m_spellInfo->Effects[i].TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET) + if (effect->TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET && + effect->TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET) break; if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc. // we need a go target in case of TARGET_GAMEOBJECT_TARGET - || (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget())) + || (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget())) return SPELL_FAILED_BAD_TARGETS; Item* pTempItem = NULL; @@ -5219,7 +5227,7 @@ SpellCastResult Spell::CheckCast(bool strict) pTempItem = m_caster->ToPlayer()->GetItemByGuid(m_targets.GetItemTargetGUID()); // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET - if (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET && + if (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET && !m_targets.GetGOTarget() && (!pTempItem || !pTempItem->GetTemplate()->LockID || !pTempItem->IsLocked())) return SPELL_FAILED_BAD_TARGETS; @@ -5246,7 +5254,7 @@ SpellCastResult Spell::CheckCast(bool strict) int32 skillValue = 0; // check lock compatibility - SpellCastResult res = CanOpenLock(i, lockId, skillId, reqSkillValue, skillValue); + SpellCastResult res = CanOpenLock(effect->EffectIndex, lockId, skillId, reqSkillValue, skillValue); if (res != SPELL_CAST_OK) return res; @@ -5274,7 +5282,7 @@ SpellCastResult Spell::CheckCast(bool strict) // This is generic summon effect case SPELL_EFFECT_SUMMON: { - SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(m_spellInfo->Effects[i].MiscValueB); + SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(effect->MiscValueB); if (!SummonProperties) break; switch (SummonProperties->Category) @@ -5408,9 +5416,9 @@ SpellCastResult Spell::CheckCast(bool strict) } } - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[i].ApplyAuraName) + switch (effect->ApplyAuraName) { case SPELL_AURA_MOD_POSSESS_PET: { @@ -5432,8 +5440,8 @@ SpellCastResult Spell::CheckCast(bool strict) if (!m_caster->GetCharmerGUID().IsEmpty()) return SPELL_FAILED_CHARMED; - if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_CHARM - || m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS) + if (effect->ApplyAuraName == SPELL_AURA_MOD_CHARM + || effect->ApplyAuraName == SPELL_AURA_MOD_POSSESS) { if (!m_caster->GetPetGUID().IsEmpty()) return SPELL_FAILED_ALREADY_HAVE_SUMMON; @@ -5456,7 +5464,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER) return SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED; - int32 damage = CalculateDamage(i, target); + int32 damage = CalculateDamage(effect->EffectIndex, target); if (damage && int32(target->getLevel()) > damage) return SPELL_FAILED_HIGHLEVEL; } @@ -5508,7 +5516,7 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_AURA_PERIODIC_MANA_LEECH: { - if (m_spellInfo->Effects[i].IsTargetingArea()) + if (effect->IsTargetingArea()) break; if (!m_targets.GetUnitTarget()) @@ -5608,14 +5616,14 @@ SpellCastResult Spell::CheckCasterAuras() const // We use bitmasks so the loop is done only once and not on every aura check below. if (m_spellInfo->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) - school_immune |= uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) - mechanic_immune |= 1 << uint32(m_spellInfo->Effects[i].MiscValue); - else if (m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) - dispel_immune |= SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[i].MiscValue)); + if (effect->ApplyAuraName == SPELL_AURA_SCHOOL_IMMUNITY) + school_immune |= uint32(effect->MiscValue); + else if (effect->ApplyAuraName == SPELL_AURA_MECHANIC_IMMUNITY) + mechanic_immune |= 1 << uint32(effect->MiscValue); + else if (effect->ApplyAuraName == SPELL_AURA_DISPEL_IMMUNITY) + dispel_immune |= SpellInfo::GetDispelMask(DispelType(effect->MiscValue)); } // immune movement impairment and loss of control if (m_spellInfo->Id == 42292 || m_spellInfo->Id == 59752 || m_spellInfo->Id == 19574) @@ -5684,9 +5692,9 @@ SpellCastResult Spell::CheckCasterAuras() const //Make a second check for spell failed so the right SPELL_FAILED message is returned. //That is needed when your casting is prevented by multiple states and you are only immune to some of them. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (AuraEffect* part = aura->GetEffect(i)) + if (AuraEffect* part = aura->GetEffect(effect->EffectIndex)) { switch (part->GetAuraType()) { @@ -5758,25 +5766,25 @@ bool Spell::CanAutoCast(Unit* target) { ObjectGuid targetguid = target->GetGUID(); - for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) + for (SpellEffectInfo const* effect : GetEffects()) { - if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA) + if (effect->Effect == SPELL_EFFECT_APPLY_AURA) { if (m_spellInfo->StackAmount <= 1) { - if (target->HasAuraEffect(m_spellInfo->Id, j)) + if (target->HasAuraEffect(m_spellInfo->Id, effect->EffectIndex)) return false; } else { - if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j)) + if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, effect->EffectIndex)) if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount) return false; } } - else if (m_spellInfo->Effects[j].IsAreaAuraEffect()) + else if (effect->IsAreaAuraEffect()) { - if (target->HasAuraEffect(m_spellInfo->Id, j)) + if (target->HasAuraEffect(m_spellInfo->Id, effect->EffectIndex)) return false; } } @@ -5921,13 +5929,13 @@ SpellCastResult Spell::CheckItems() { // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example SpellCastResult failReason = SPELL_CAST_OK; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster - if (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET) + if (effect->TargetA.GetTarget() == TARGET_UNIT_PET) continue; - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL) + if (effect->Effect == SPELL_EFFECT_HEAL) { if (m_targets.GetUnitTarget()->IsFullHealth()) { @@ -5942,15 +5950,15 @@ SpellCastResult Spell::CheckItems() } // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_ENERGIZE) + if (effect->Effect == SPELL_EFFECT_ENERGIZE) { - if (m_spellInfo->Effects[i].MiscValue < 0 || m_spellInfo->Effects[i].MiscValue >= int8(MAX_POWERS)) + if (effect->MiscValue < 0 || effect->MiscValue >= int8(MAX_POWERS)) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; continue; } - Powers power = Powers(m_spellInfo->Effects[i].MiscValue); + Powers power = Powers(effect->MiscValue); if (m_targets.GetUnitTarget()->GetPower(power) == m_targets.GetUnitTarget()->GetMaxPower(power)) { failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; @@ -6048,34 +6056,34 @@ SpellCastResult Spell::CheckItems() } // special checks for spell effects - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - switch (m_spellInfo->Effects[i].Effect) + switch (effect->Effect) { case SPELL_EFFECT_CREATE_ITEM: case SPELL_EFFECT_CREATE_ITEM_2: { - if (!IsTriggered() && m_spellInfo->Effects[i].ItemType) + if (!IsTriggered() && effect->ItemType) { ItemPosCountVec dest; - InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1); + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1); if (msg != EQUIP_ERR_OK) { - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType); + ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(effect->ItemType); /// @todo Needs review if (pProto && !(pProto->ItemLimitCategory)) { - player->SendEquipError(msg, NULL, NULL, m_spellInfo->Effects[i].ItemType); + player->SendEquipError(msg, NULL, NULL, effect->ItemType); return SPELL_FAILED_DONT_REPORT; } else { if (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (m_spellInfo->SpellFamilyFlags[0] & 0x40000000))) return SPELL_FAILED_TOO_MANY_OF_ITEM; - else if (!(player->HasItemCount(m_spellInfo->Effects[i].ItemType))) + else if (!(player->HasItemCount(effect->ItemType))) return SPELL_FAILED_TOO_MANY_OF_ITEM; - else - player->CastSpell(m_caster, m_spellInfo->Effects[EFFECT_1].CalcValue(), false); // move this to anywhere + else if (SpellEffectInfo const* efi = GetEffect(EFFECT_1)) + player->CastSpell(m_caster, efi->CalcValue(), false); // move this to anywhere return SPELL_FAILED_DONT_REPORT; } } @@ -6083,7 +6091,7 @@ SpellCastResult Spell::CheckItems() break; } case SPELL_EFFECT_ENCHANT_ITEM: - if (m_spellInfo->Effects[i].ItemType && m_targets.GetItemTarget() + if (effect->ItemType && m_targets.GetItemTarget() && (m_targets.GetItemTarget()->IsVellum())) { // cannot enchant vellum for other player @@ -6093,10 +6101,10 @@ SpellCastResult Spell::CheckItems() if (m_CastItem && m_CastItem->GetTemplate()->Flags[0] & ITEM_PROTO_FLAG_TRIGGERED_CAST) return SPELL_FAILED_TOTEM_CATEGORY; ItemPosCountVec dest; - InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, m_spellInfo->Effects[i].ItemType, 1); + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1); if (msg != EQUIP_ERR_OK) { - player->SendEquipError(msg, NULL, NULL, m_spellInfo->Effects[i].ItemType); + player->SendEquipError(msg, NULL, NULL, effect->ItemType); return SPELL_FAILED_DONT_REPORT; } } @@ -6123,7 +6131,7 @@ SpellCastResult Spell::CheckItems() } } - SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(m_spellInfo->Effects[i].MiscValue); + SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(effect->MiscValue); // do not allow adding usable enchantments to items that have use effect already if (enchantEntry) { @@ -6168,7 +6176,7 @@ SpellCastResult Spell::CheckItems() // Not allow enchant in trade slot for some enchant type if (item->GetOwner() != m_caster) { - uint32 enchant_id = m_spellInfo->Effects[i].MiscValue; + uint32 enchant_id = effect->MiscValue; SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) return SPELL_FAILED_ERROR; @@ -6285,7 +6293,7 @@ SpellCastResult Spell::CheckItems() } case SPELL_EFFECT_CREATE_MANA_GEM: { - uint32 item_id = m_spellInfo->Effects[i].ItemType; + uint32 item_id = effect->ItemType; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id); if (!pProto) @@ -6457,9 +6465,9 @@ bool Spell::UpdatePointers() WorldObject* transport = NULL; // update effect destinations (in case of moved transport dest target) - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + for (SpellEffectInfo const* effect : GetEffects()) { - SpellDestination& dest = m_destTargets[effIndex]; + SpellDestination& dest = m_destTargets[effect->EffectIndex]; if (!dest._transportGUID) continue; @@ -6490,7 +6498,11 @@ CurrentSpellTypes Spell::GetCurrentContainer() const bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* losPosition) const { - switch (m_spellInfo->Effects[eff].ApplyAuraName) + SpellEffectInfo const* effect = GetEffect(eff); + if (!effect) + return false; + + switch (effect->ApplyAuraName) { case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CHARM: @@ -6520,7 +6532,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo /// @todo shit below shouldn't be here, but it's temporary //Check targets for LOS visibility (except spells without range limitations) - switch (m_spellInfo->Effects[eff].Effect) + switch (effect->Effect) { case SPELL_EFFECT_RESURRECT_NEW: // player far away, maybe his corpse near? @@ -6731,21 +6743,19 @@ bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const void Spell::HandleLaunchPhase() { // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { // don't do anything for empty effect - if (!m_spellInfo->Effects[i].IsEffect()) + if (!effect->IsEffect()) continue; - HandleEffects(NULL, NULL, NULL, i, SPELL_EFFECT_HANDLE_LAUNCH); + HandleEffects(NULL, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_LAUNCH); } float multiplier[MAX_SPELL_EFFECTS]; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_applyMultiplierMask & (1 << i)) - multiplier[i] = m_spellInfo->Effects[i].CalcDamageMultiplier(m_originalCaster, this); - - bool usesAmmo = (m_spellInfo->AttributesCu & SPELL_ATTR0_CU_DIRECT_DAMAGE) != 0; + for (SpellEffectInfo const* effect : GetEffects()) + if (m_applyMultiplierMask & (1 << effect->EffectIndex)) + multiplier[effect->EffectIndex] = effect->CalcDamageMultiplier(m_originalCaster, this); for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { @@ -6755,31 +6765,6 @@ void Spell::HandleLaunchPhase() if (!mask) continue; - // do not consume ammo anymore for Hunter's volley spell - if (IsTriggered() && m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->IsTargetingArea()) - usesAmmo = false; - - if (usesAmmo) - { - bool ammoTaken = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (!(mask & 1<<i)) - continue; - switch (m_spellInfo->Effects[i].Effect) - { - case SPELL_EFFECT_SCHOOL_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE: - case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: - case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: - case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - ammoTaken=true; - TakeAmmo(); - } - if (ammoTaken) - break; - } - } DoAllEffectOnLaunchTarget(target, multiplier); } } @@ -6796,18 +6781,18 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) if (!unit) return; - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if (targetInfo.effectMask & (1<<i)) + if (targetInfo.effectMask & (1<<effect->EffectIndex)) { m_damage = 0; m_healing = 0; - HandleEffects(unit, NULL, NULL, i, SPELL_EFFECT_HANDLE_LAUNCH_TARGET); + HandleEffects(unit, NULL, NULL, effect->EffectIndex, SPELL_EFFECT_HANDLE_LAUNCH_TARGET); if (m_damage > 0) { - if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) + if (effect->IsTargetingArea() || effect->IsAreaAuraEffect() || effect->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) { m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -6822,10 +6807,10 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) } } - if (m_applyMultiplierMask & (1 << i)) + if (m_applyMultiplierMask & (1 << effect->EffectIndex)) { - m_damage = int32(m_damage * m_damageMultipliers[i]); - m_damageMultipliers[i] *= multiplier[i]; + m_damage = int32(m_damage * m_damageMultipliers[effect->EffectIndex]); + m_damageMultipliers[effect->EffectIndex] *= multiplier[effect->EffectIndex]; } targetInfo.damage += m_damage; } @@ -6845,6 +6830,10 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk if (!lockInfo) return SPELL_FAILED_BAD_TARGETS; + SpellEffectInfo const* effect = GetEffect(effIndex); + if (!effect) + return SPELL_FAILED_BAD_TARGETS; // no idea about correct error + bool reqKey = false; // some locks not have reqs for (int j = 0; j < MAX_LOCK_CASE; ++j) @@ -6863,7 +6852,7 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk reqKey = true; // wrong locktype, skip - if (uint32(m_spellInfo->Effects[effIndex].MiscValue) != lockInfo->Index[j]) + if (uint32(effect->MiscValue) != lockInfo->Index[j]) continue; skillId = SkillByLockType(LockType(lockInfo->Index[j])); @@ -6878,8 +6867,8 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk // skill bonus provided by casting spell (mostly item spells) // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.) - if (m_spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || m_spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET) - skillValue += m_spellInfo->Effects[effIndex].CalcValue(); + if (effect->TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || effect->TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET) + skillValue += effect->CalcValue(); if (skillValue < reqSkillValue) return SPELL_FAILED_LOW_CASTLEVEL; @@ -6898,17 +6887,15 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk void Spell::SetSpellValue(SpellValueMod mod, int32 value) { + if (mod < SPELLVALUE_BASE_POINT_END) + { + if (SpellEffectInfo const* effect = GetEffect(mod)) + m_spellValue->EffectBasePoints[mod] = effect->CalcBaseValue(value); + return; + } + switch (mod) { - case SPELLVALUE_BASE_POINT0: - m_spellValue->EffectBasePoints[0] = m_spellInfo->Effects[EFFECT_0].CalcBaseValue(value); - break; - case SPELLVALUE_BASE_POINT1: - m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(value); - break; - case SPELLVALUE_BASE_POINT2: - m_spellValue->EffectBasePoints[2] = m_spellInfo->Effects[EFFECT_2].CalcBaseValue(value); - break; case SPELLVALUE_RADIUS_MOD: m_spellValue->RadiusMod = (float)value / 10000; break; @@ -6931,7 +6918,7 @@ void Spell::FinishTargetProcessing() SendLogExecute(); } -void Spell::InitEffectExecuteData(uint8 effIndex) +void Spell::InitEffectExecuteData(uint32 effIndex) { ASSERT(effIndex < MAX_SPELL_EFFECTS); if (!m_effectExecuteData[effIndex]) @@ -7193,9 +7180,9 @@ bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByA { bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER - for (uint8 i = 0;i < MAX_SPELL_EFFECTS; ++i) + for (SpellEffectInfo const* effect : GetEffects()) { - if ((effMask & (1 << i)) && (!only_on_caster || (m_spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_CASTER))) + if ((effMask & (1 << effect->EffectIndex)) && (!only_on_caster || (effect->TargetA.GetTarget() == TARGET_UNIT_CASTER))) return true; } return false; @@ -7236,19 +7223,23 @@ void Spell::PrepareTriggersExecutedOnHit() continue; SpellInfo const* auraSpellInfo = (*i)->GetSpellInfo(); uint32 auraSpellIdx = (*i)->GetEffIndex(); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraSpellInfo->Effects[auraSpellIdx].TriggerSpell)) + // todo 6.x + if (SpellEffectInfo const* auraEffect = auraSpellInfo->GetEffect(m_caster->GetMap()->GetDifficulty(), auraSpellIdx)) { - // calculate the chance using spell base amount, because aura amount is not updated on combo-points change - // this possibly needs fixing - int32 auraBaseAmount = (*i)->GetBaseAmount(); - // proc chance is stored in effect amount - int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); - // build trigger and add to the list - HitTriggerSpell spellTriggerInfo; - spellTriggerInfo.triggeredSpell = spellInfo; - spellTriggerInfo.triggeredByAura = auraSpellInfo; - spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); - m_hitTriggerSpells.push_back(spellTriggerInfo); + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(auraEffect->TriggerSpell)) + { + // calculate the chance using spell base amount, because aura amount is not updated on combo-points change + // this possibly needs fixing + int32 auraBaseAmount = (*i)->GetBaseAmount(); + // proc chance is stored in effect amount + int32 chance = m_caster->CalculateSpellDamage(NULL, auraSpellInfo, auraSpellIdx, &auraBaseAmount); + // build trigger and add to the list + HitTriggerSpell spellTriggerInfo; + spellTriggerInfo.triggeredSpell = spellInfo; + spellTriggerInfo.triggeredByAura = auraSpellInfo; + spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount(); + m_hitTriggerSpells.push_back(spellTriggerInfo); + } } } } @@ -7321,6 +7312,16 @@ void Spell::CancelGlobalCooldown() m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); } +bool Spell::HasEffect(SpellEffectName effect) const +{ + for (SpellEffectInfo const* eff : GetEffects()) + { + if (eff->IsEffect(effect)) + return true; + } + return false; +} + namespace Trinity { |