diff options
| author | Rat <gmstreetrat@gmail.com> | 2014-11-16 14:20:01 +0100 |
|---|---|---|
| committer | Rat <gmstreetrat@gmail.com> | 2014-11-16 14:20:01 +0100 |
| commit | 588143b9b69a81eee69d5fb3b9690c8aafc1a38f (patch) | |
| tree | a5ff6545b7360592475e4272147216a43218e91c /src/server/game/Spells | |
| parent | c375748b7636fe88f1daf37197dc9da3d4a674a1 (diff) | |
Core/Spells: Spell system updates (don't even try to compile this)
Diffstat (limited to 'src/server/game/Spells')
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 627 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.h | 31 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 145 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.h | 35 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 100 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellMgr.h | 6 |
7 files changed, 460 insertions, 486 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 { diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index dc07449c41f..ee31326808f 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -192,7 +192,7 @@ class SpellCastTargets struct SpellValue { explicit SpellValue(SpellInfo const* proto); - int32 EffectBasePoints[MAX_SPELL_EFFECTS]; + std::vector<int32> EffectBasePoints; uint32 MaxAffectedTargets; float RadiusMod; uint8 AuraStackAmount; @@ -377,7 +377,7 @@ class Spell void SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); void SelectImplicitTrajTargets(SpellEffIndex effIndex); - void SelectEffectTypeImplicitTargets(uint8 effIndex); + void SelectEffectTypeImplicitTargets(uint32 effIndex); uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionList* condList); template<class SEARCHER> void SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* referer, Position const* pos, float radius); @@ -394,7 +394,6 @@ class Spell void cast(bool skipCheck = false); void finish(bool ok = true); void TakePower(); - void TakeAmmo(); void TakeRunePower(bool didHit); void TakeReagents(); @@ -503,6 +502,18 @@ class Spell void CleanupTargetList(); void SetSpellValue(SpellValueMod mod, int32 value); + + SpellEffectInfoVector GetEffects() const { return difficultyEffects; } + SpellEffectInfo const* GetEffect(uint32 index) const + { + if (index >= difficultyEffects.size()) + return nullptr; + + return difficultyEffects[index]; + } + + bool HasEffect(SpellEffectName effect) const; + protected: bool HasGlobalCooldown() const; void TriggerGlobalCooldown(); @@ -591,7 +602,7 @@ class Spell uint64 timeDelay; SpellMissInfo missCondition:8; SpellMissInfo reflectResult:8; - uint8 effectMask:8; + uint32 effectMask:32; bool processed:1; bool alive:1; bool crit:1; @@ -599,13 +610,13 @@ class Spell int32 damage; }; std::list<TargetInfo> m_UniqueTargetInfo; - uint8 m_channelTargetEffectMask; // Mask req. alive targets + uint32 m_channelTargetEffectMask; // Mask req. alive targets struct GOTargetInfo { ObjectGuid targetGUID; uint64 timeDelay; - uint8 effectMask:8; + uint32 effectMask:32; bool processed:1; }; std::list<GOTargetInfo> m_UniqueGOTargetInfo; @@ -613,7 +624,7 @@ class Spell struct ItemTargetInfo { Item *item; - uint8 effectMask; + uint32 effectMask; }; std::list<ItemTargetInfo> m_UniqueItemInfo; @@ -638,7 +649,7 @@ class Spell void FinishTargetProcessing(); // spell execution log - void InitEffectExecuteData(uint8 effIndex); + void InitEffectExecuteData(uint32 effIndex); void CheckEffectExecuteData(); // Scripting system @@ -689,7 +700,7 @@ class Spell SpellInfo const* m_triggeredByAuraSpell; bool m_skipCheck; - uint8 m_auraScaleMask; + uint32 m_auraScaleMask; PathGenerator m_preGeneratedPath; ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]; @@ -704,6 +715,8 @@ class Spell Spell(Spell const& right) = delete; Spell& operator=(Spell const& right) = delete; + + SpellEffectInfoVector difficultyEffects; }; namespace Trinity diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9c12abbe6e2..c1e588c7edf 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -359,7 +359,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) { // Consumption case 28865: - damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); + damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == DIFFICULTY_NONE ? 2750 : 4250); break; // percent from health with min case 25599: // Thundercrash diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index cc88cc41e5a..3c4cf37b4e3 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -344,7 +344,7 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo con SpellScalingEntry const* scaling = spellInfo->GetSpellScaling(); _spellInfo = spellInfo; - _effIndex = _effect ? _effect->EffectIndex : effIndex; + EffectIndex = _effect ? _effect->EffectIndex : effIndex; Effect = _effect ? _effect->Effect : 0; ApplyAuraName = _effect ? _effect->EffectAura : 0; ApplyAuraPeriod = _effect ? _effect->EffectAuraPeriod : 0; @@ -368,9 +368,9 @@ SpellEffectInfo::SpellEffectInfo(SpellEntry const* /*spellEntry*/, SpellInfo con SpellClassMask = _effect ? _effect->EffectSpellClassMask : flag128(); ImplicitTargetConditions = NULL; // TODO: 6.x these values are no longer in dbc - ScalingMultiplier = /*scaling ? scaling->Multiplier[_effIndex] :*/ 0.0f; - DeltaScalingMultiplier = /*scaling ? scaling->RandomMultiplier[_effIndex] :*/ 0.0f; - ComboScalingMultiplier = /*scaling ? scaling->OtherMultiplier[_effIndex] :*/ 0.0f; + ScalingMultiplier = /*scaling ? scaling->Multiplier[EffectIndex] :*/ 0.0f; + DeltaScalingMultiplier = /*scaling ? scaling->RandomMultiplier[EffectIndex] :*/ 0.0f; + ComboScalingMultiplier = /*scaling ? scaling->OtherMultiplier[EffectIndex] :*/ 0.0f; } bool SpellEffectInfo::IsEffect() const @@ -378,7 +378,7 @@ bool SpellEffectInfo::IsEffect() const return Effect != 0; } -bool SpellEffectInfo::IsEffect(SpellEffects effectName) const +bool SpellEffectInfo::IsEffect(SpellEffectName effectName) const { return Effect == uint32(effectName); } @@ -441,7 +441,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const if (caster) { int32 level = caster->getLevel(); - if (target && _spellInfo->IsPositiveEffect(_effIndex) && (Effect == SPELL_EFFECT_APPLY_AURA)) + if (target && _spellInfo->IsPositiveEffect(EffectIndex) && (Effect == SPELL_EFFECT_APPLY_AURA)) level = target->getLevel(); if (GtSpellScalingEntry const* gtScaling = sGtSpellScalingStore.LookupEntry((_spellInfo->ScalingClass != -1 ? _spellInfo->ScalingClass - 1 : MAX_CLASSES - 1) * 100 + level - 1)) @@ -508,7 +508,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const if (uint8 comboPoints = caster->m_movedPlayer->GetComboPoints()) value += comboDamage * comboPoints; - value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value); + value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value); // amount multiplication based on caster's level /* REVIEW - MERGE <<<<<<< HEAD @@ -862,10 +862,12 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_UNIT}, // 182 SPELL_EFFECT_182 }; -SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects) +SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectInfoMap effects) { Id = spellEntry->ID; + Effects = effects; + SpellName = spellEntry->Name_lang; //Rank = spellEntry->Rank; RuneCostID = spellEntry->RuneCostID; @@ -916,10 +918,6 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe SpellIconID = _misc ? _misc->SpellIconID : 0; ActiveIconID = _misc ? _misc->ActiveIconID : 0; - // SpellDifficultyEntry - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - Effects[i] = SpellEffectInfo(spellEntry, this, i, effects[i]); - // SpellScalingEntry SpellScalingEntry const* _scaling = GetSpellScaling(); CastTimeMin = _scaling ? _scaling->CastTimeMin : 0; @@ -1040,27 +1038,35 @@ uint32 SpellInfo::GetCategory() const return CategoryEntry ? CategoryEntry->ID : 0; } -bool SpellInfo::HasEffect(SpellEffects effect) const +bool SpellInfo::HasEffect(uint32 difficulty, SpellEffectName effect) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect(effect)) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + if ((*itr)->IsEffect(effect)) return true; + } return false; } -bool SpellInfo::HasAura(AuraType aura) const +bool SpellInfo::HasAura(uint32 difficulty, AuraType aura) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsAura(aura)) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + if ((*itr)->IsAura(aura)) return true; - return false; + } } -bool SpellInfo::HasAreaAuraEffect() const +bool SpellInfo::HasAreaAuraEffect(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsAreaAuraEffect()) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + if ((*itr)->IsAreaAuraEffect()) return true; + } return false; } @@ -1085,13 +1091,14 @@ bool SpellInfo::IsQuestTame() const return Effects[0].Effect == SPELL_EFFECT_THREAT && Effects[1].Effect == SPELL_EFFECT_APPLY_AURA && Effects[1].ApplyAuraName == SPELL_AURA_DUMMY; } -bool SpellInfo::IsProfessionOrRiding() const +bool SpellInfo::IsProfessionOrRiding(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if ((*itr)->Effect == SPELL_EFFECT_SKILL) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = (*itr)->MiscValue; if (IsProfessionOrRidingSkill(skill)) return true; @@ -1100,13 +1107,14 @@ bool SpellInfo::IsProfessionOrRiding() const return false; } -bool SpellInfo::IsProfession() const +bool SpellInfo::IsProfession(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if ((*itr)->Effect == SPELL_EFFECT_SKILL) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = (*itr)->MiscValue; if (IsProfessionSkill(skill)) return true; @@ -1115,13 +1123,14 @@ bool SpellInfo::IsProfession() const return false; } -bool SpellInfo::IsPrimaryProfession() const +bool SpellInfo::IsPrimaryProfession(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) { - if (Effects[i].Effect == SPELL_EFFECT_SKILL) + if ((*itr)->Effect == SPELL_EFFECT_SKILL) { - uint32 skill = Effects[i].MiscValue; + uint32 skill = (*itr)->MiscValue; if (IsPrimaryProfessionSkill(skill)) return true; @@ -1130,9 +1139,9 @@ bool SpellInfo::IsPrimaryProfession() const return false; } -bool SpellInfo::IsPrimaryProfessionFirstRank() const +bool SpellInfo::IsPrimaryProfessionFirstRank(uint32 difficulty) const { - return IsPrimaryProfession() && GetRank() == 1; + return IsPrimaryProfession(difficulty) && GetRank() == 1; } bool SpellInfo::IsAbilityLearnedWithProfession() const @@ -1163,20 +1172,26 @@ bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const return false; } -bool SpellInfo::IsAffectingArea() const +bool SpellInfo::IsAffectingArea(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect() && (Effects[i].IsTargetingArea() || Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || Effects[i].IsAreaAuraEffect())) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + if ((*itr)->IsEffect() && ((*itr)->IsTargetingArea() || (*itr)->IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || (*itr)->IsAreaAuraEffect())) return true; + } return false; } // checks if spell targets are selected from area, doesn't include spell effects in check (like area wide auras for example) -bool SpellInfo::IsTargetingArea() const +bool SpellInfo::IsTargetingArea(uint32 difficulty) const { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (Effects[i].IsEffect() && Effects[i].IsTargetingArea()) + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + for (SpellEffectInfoVector::const_iterator itr = effects.begin(); itr != effects.end(); ++itr) + { + if ((*itr)->IsEffect() && (*itr)->IsTargetingArea()) return true; + } return false; } @@ -2931,16 +2946,46 @@ SpellCooldownsEntry const* SpellInfo::GetSpellCooldowns() const void SpellInfo::_UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint32 d = 0; d < DIFFICULTY_MAX; ++d) { - ConditionList* cur = Effects[i].ImplicitTargetConditions; - if (!cur) - continue; - for (uint8 j = i; j < MAX_SPELL_EFFECTS; ++j) + for (uint32 i = 0; i < Effects.size(); ++i) { - if (Effects[j].ImplicitTargetConditions == cur) - Effects[j].ImplicitTargetConditions = NULL; + if (SpellEffectInfo const* effect = GetEffect(d, i)) + { + ConditionList* cur = effect->ImplicitTargetConditions; + if (!cur) + continue; + for (uint8 j = i; j < Effects.size(); ++j) + { + if (SpellEffectInfo const* eff = GetEffect(d, j)) + { + if (eff->ImplicitTargetConditions == cur) + const_cast<SpellEffectInfo*>(eff)->ImplicitTargetConditions = NULL; + } + } + delete cur; + } } - delete cur; } } + +SpellEffectInfoVector SpellInfo::GetEffectsForDifficulty(uint32 difficulty) const +{ + // downscale difficulty if original was not found + for (; difficulty >= DIFFICULTY_NONE; --difficulty) + { + SpellEffectInfoMap::const_iterator itr = Effects.find(difficulty); + if (itr != Effects.end()) + return itr->second; + } + return SpellEffectInfoVector(); +} + +SpellEffectInfo const* SpellInfo::GetEffect(uint32 difficulty, uint32 index) const +{ + SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty); + if (index >= effects.size()) + return nullptr; + + return effects[index]; +}
\ No newline at end of file diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 1fad30dd23b..36c8523dbf2 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -230,8 +230,8 @@ private: class SpellEffectInfo { SpellInfo const* _spellInfo; - uint8 _effIndex; public: + uint32 EffectIndex; uint32 Effect; uint32 ApplyAuraName; uint32 ApplyAuraPeriod; @@ -259,14 +259,14 @@ public: float DeltaScalingMultiplier; float ComboScalingMultiplier; - SpellEffectInfo() : _spellInfo(NULL), _effIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0), DieSides(0), + SpellEffectInfo() : _spellInfo(NULL), EffectIndex(0), Effect(0), ApplyAuraName(0), ApplyAuraPeriod(0), DieSides(0), RealPointsPerLevel(0), BasePoints(0), PointsPerResource(0), Amplitude(0), ChainAmplitude(0), BonusCoefficient(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(NULL), ChainTargets(0), ItemType(0), TriggerSpell(0), ImplicitTargetConditions(NULL) {} SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex, SpellEffectEntry const* effect); bool IsEffect() const; - bool IsEffect(SpellEffects effectName) const; + bool IsEffect(SpellEffectName effectName) const; bool IsAura() const; bool IsAura(AuraType aura) const; bool IsTargetingArea() const; @@ -299,6 +299,9 @@ private: static StaticData _data[TOTAL_SPELL_EFFECTS]; }; +typedef std::vector<SpellEffectInfo const*> SpellEffectInfoVector; +typedef std::unordered_map<uint32, SpellEffectInfoVector> SpellEffectInfoMap; + class SpellInfo { public: @@ -403,7 +406,6 @@ public: int32 ScalingClass; float CoefBase; int32 CoefLevelBase; - SpellEffectInfo Effects[MAX_SPELL_EFFECTS]; uint32 ExplicitTargetMask; SpellChainNode const* ChainEntry; @@ -425,26 +427,26 @@ public: SpellTotemsEntry const* GetSpellTotems() const; SpellMiscEntry const* GetSpellMisc() const; - SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effects); + SpellInfo(SpellEntry const* spellEntry, SpellEffectInfoMap effects); ~SpellInfo(); uint32 GetCategory() const; - bool HasEffect(SpellEffects effect) const; - bool HasAura(AuraType aura) const; - bool HasAreaAuraEffect() const; + bool HasEffect(uint32 difficulty, SpellEffectName effect) const; + bool HasAura(uint32 difficulty, AuraType aura) const; + bool HasAreaAuraEffect(uint32 difficulty) const; bool IsExplicitDiscovery() const; bool IsLootCrafting() const; bool IsQuestTame() const; - bool IsProfessionOrRiding() const; - bool IsProfession() const; - bool IsPrimaryProfession() const; - bool IsPrimaryProfessionFirstRank() const; + bool IsProfessionOrRiding(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsProfession(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsPrimaryProfession(uint32 difficulty = DIFFICULTY_NONE) const; + bool IsPrimaryProfessionFirstRank(uint32 difficulty = DIFFICULTY_NONE) const; bool IsAbilityLearnedWithProfession() const; bool IsAbilityOfSkillType(uint32 skillType) const; - bool IsAffectingArea() const; - bool IsTargetingArea() const; + bool IsAffectingArea(uint32 difficulty) const; + bool IsTargetingArea(uint32 difficulty) const; bool NeedsExplicitUnitTarget() const; bool NeedsToBeTriggeredByCaster(SpellInfo const* triggeringSpell) const; @@ -529,6 +531,11 @@ public: // unloading helpers void _UnloadImplicitTargetConditionLists(); + + SpellEffectInfoVector GetEffectsForDifficulty(uint32 difficulty) const; + SpellEffectInfo const* GetEffect(uint32 difficulty, uint32 index) const; + + SpellEffectInfoMap Effects; }; #endif // _SPELLINFO_H diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3b7ab7abe30..e0f43097abd 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -453,81 +453,6 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg return true; } -uint32 SpellMgr::GetSpellDifficultyId(uint32 spellId) const -{ - SpellDifficultySearcherMap::const_iterator i = mSpellDifficultySearcherMap.find(spellId); - return i == mSpellDifficultySearcherMap.end() ? 0 : i->second; -} - -void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id) -{ - if (uint32 i = GetSpellDifficultyId(spellId)) - TC_LOG_ERROR("spells", "SpellMgr::SetSpellDifficultyId: Spell %u has already spellDifficultyId %u. Will override with spellDifficultyId %u.", spellId, i, id); - mSpellDifficultySearcherMap[spellId] = id; -} - -// TODO: 6.x adapt to new spell diff system -uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const -{ - /*if (!GetSpellInfo(spellId)) - return spellId; - - if (!caster || !caster->GetMap() || !caster->GetMap()->IsDungeon()) - return spellId; - - uint32 mode = uint32(caster->GetMap()->GetSpawnMode()); - if (mode >= MAX_DIFFICULTY) - { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect Difficulty for spell %u.", spellId); - return spellId; //return source spell - } - - uint32 difficultyId = GetSpellDifficultyId(spellId); - if (!difficultyId) - return spellId; //return source spell, it has only REGULAR_DIFFICULTY - - SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId); - if (!difficultyEntry) - { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen.", spellId); - return spellId; //return source spell - } - - if (difficultyEntry->SpellID[mode] <= 0 && mode > DUNGEON_DIFFICULTY_HEROIC) - { - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is NULL, using mode %u", spellId, mode, mode - 2); - mode -= 2; - } - - if (difficultyEntry->SpellID[mode] <= 0) - { - TC_LOG_ERROR("sql.sql", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is 0. Check spelldifficulty_dbc!", spellId, mode); - return spellId; - } - - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spellid for spell %u in mode %u is %d", spellId, mode, difficultyEntry->SpellID[mode]); - return uint32(difficultyEntry->SpellID[mode]); - */ - return 0; -} - -SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const -{ - if (!spell) - return NULL; - - uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster); - SpellInfo const* newSpell = GetSpellInfo(newSpellId); - if (!newSpell) - { - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: spell %u not found. Check spelldifficulty_dbc!", newSpellId); - return spell; - } - - TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is %u (original %u)", newSpell->Id, spell->Id); - return newSpell; -} - SpellChainNode const* SpellMgr::GetSpellChainNode(uint32 spell_id) const { SpellChainMap::const_iterator itr = mSpellChains.find(spell_id); @@ -2791,18 +2716,7 @@ void SpellMgr::LoadSpellAreas() TC_LOG_INFO("server.loading", ">> Loaded %u spell area requirements in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -// Temporary structure to hold spell effect entries for faster loading -struct SpellEffectArray -{ - SpellEffectArray() - { - effects[0] = NULL; - effects[1] = NULL; - effects[2] = NULL; - } - - SpellEffectEntry const* effects[MAX_SPELL_EFFECTS]; -}; +typedef std::vector<SpellEffectEntry const*> SpellEffectVector; void SpellMgr::LoadSpellInfoStore() { @@ -2811,7 +2725,7 @@ void SpellMgr::LoadSpellInfoStore() UnloadSpellInfoStore(); mSpellInfoMap.resize(sSpellStore.GetNumRows(), NULL); - std::map<uint32, SpellEffectArray> effectsBySpell; + std::map<uint32, SpellEffectInfoMap> effectsBySpell; for (uint32 i = 0; i < sSpellEffectStore.GetNumRows(); ++i) { @@ -2819,17 +2733,17 @@ void SpellMgr::LoadSpellInfoStore() if (!effect) continue; - // TODO: 6.x implement dynamic spell effect storage and remove MAX_SPELL_EFFECTS - // This is a temporary fix to avoid crash when loading spells if (effect->EffectIndex >= MAX_SPELL_EFFECTS) + { + TC_LOG_ERROR("server.loading", "Spell %u has invalid EffectIndex %u, max is %u, skipped", i, effect->EffectIndex, uint32(MAX_SPELL_EFFECTS)); continue; - - effectsBySpell[effect->SpellID].effects[effect->EffectIndex] = effect; + } + effectsBySpell[effect->SpellID][effect->DifficultyID][effect->EffectIndex] = effect; } for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i) if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i)) - mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i].effects); + mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i]); TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in %u ms", GetMSTimeDiffToNow(oldMSTime)); } diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 053935a53cb..5be0cfda84c 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -617,12 +617,6 @@ class SpellMgr // Spell correctness for client using static bool IsSpellValid(SpellInfo const* spellInfo, Player* player = NULL, bool msg = true); - // Spell difficulty - uint32 GetSpellDifficultyId(uint32 spellId) const; - void SetSpellDifficultyId(uint32 spellId, uint32 id); - uint32 GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) const; - SpellInfo const* GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const; - // Spell Ranks table SpellChainNode const* GetSpellChainNode(uint32 spell_id) const; uint32 GetFirstSpellInChain(uint32 spell_id) const; |
