aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQAston <qaston@gmail.com>2011-07-26 23:00:23 +0200
committerQAston <qaston@gmail.com>2011-07-26 23:00:23 +0200
commit29c228a80170e4264129d4e3bed4d2fc41aca5a7 (patch)
tree02a75815a4f016d17c8f9ddb109897793a3a04dd
parentb2698d699e34736dde1d37b568299161562aa369 (diff)
Core/Spells: Add SpellInfo class to store static data and methods for spells. This class is going to replace SpellEntry use in core. SpellInfo class includes all spell-related functions which resided in SpellMgr, and makes them much easier to access, reuse or add new stuff. Another advantage is that you no longer have to lookup db/dbc data by entry or index, because such data can now be included in the new class. Thanks to that, TC will have no problems on drastic spell dbc format change in 4.x.
-rw-r--r--src/server/game/Spells/SpellInfo.cpp1942
-rw-r--r--src/server/game/Spells/SpellInfo.h360
2 files changed, 2302 insertions, 0 deletions
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
new file mode 100644
index 00000000000..8e71d3bcda9
--- /dev/null
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -0,0 +1,1942 @@
+/*
+ * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "SpellInfo.h"
+#include "SpellMgr.h"
+#include "DbcStores.h"
+
+SpellImplicitTargetInfo::SpellImplicitTargetInfo(uint32 target)
+{
+ _target = Targets(target);
+}
+
+bool SpellImplicitTargetInfo::IsArea() const
+{
+ return Area[_target];
+}
+
+SpellSelectTargetTypes SpellImplicitTargetInfo::GetType() const
+{
+ return Type[_target];
+}
+
+bool SpellImplicitTargetInfo::IsPosition(uint32 targetType)
+{
+ switch (SpellImplicitTargetInfo::Type[targetType])
+ {
+ case TARGET_TYPE_DEST_CASTER:
+ case TARGET_TYPE_DEST_TARGET:
+ case TARGET_TYPE_DEST_DEST:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+SpellImplicitTargetInfo::operator Targets() const
+{
+ return _target;
+}
+
+bool SpellImplicitTargetInfo::InitStaticData()
+{
+ InitAreaData();
+ InitTypeData();
+ return true;
+}
+
+void SpellImplicitTargetInfo::InitAreaData()
+{
+ for (int32 i = 0; i < TOTAL_SPELL_TARGETS; ++i)
+ {
+ switch (i)
+ {
+ case TARGET_UNIT_AREA_ENEMY_DST:
+ case TARGET_UNIT_AREA_ENEMY_SRC:
+ case TARGET_UNIT_AREA_ALLY_DST:
+ case TARGET_UNIT_AREA_ALLY_SRC:
+ case TARGET_UNIT_AREA_ENTRY_DST:
+ case TARGET_UNIT_AREA_ENTRY_SRC:
+ case TARGET_UNIT_AREA_PARTY_DST:
+ case TARGET_UNIT_AREA_PARTY_SRC:
+ case TARGET_UNIT_TARGET_ALLY_PARTY:
+ case TARGET_UNIT_PARTY_CASTER:
+ case TARGET_UNIT_CONE_ENEMY:
+ case TARGET_UNIT_CONE_ALLY:
+ case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
+ case TARGET_UNIT_AREA_PATH:
+ case TARGET_GAMEOBJECT_AREA_PATH:
+ case TARGET_UNIT_RAID_CASTER:
+ Area[i] = true;
+ break;
+ default:
+ Area[i] = false;
+ break;
+ }
+ }
+}
+
+void SpellImplicitTargetInfo::InitTypeData()
+{
+ for (uint8 i = 0; i < TOTAL_SPELL_TARGETS; ++i)
+ {
+ switch (i)
+ {
+ case TARGET_UNIT_CASTER:
+ case TARGET_UNIT_CASTER_FISHING:
+ case TARGET_UNIT_MASTER:
+ case TARGET_UNIT_PET:
+ case TARGET_UNIT_PARTY_CASTER:
+ case TARGET_UNIT_RAID_CASTER:
+ case TARGET_UNIT_VEHICLE:
+ case TARGET_UNIT_PASSENGER_0:
+ case TARGET_UNIT_PASSENGER_1:
+ case TARGET_UNIT_PASSENGER_2:
+ case TARGET_UNIT_PASSENGER_3:
+ case TARGET_UNIT_PASSENGER_4:
+ case TARGET_UNIT_PASSENGER_5:
+ case TARGET_UNIT_PASSENGER_6:
+ case TARGET_UNIT_PASSENGER_7:
+ case TARGET_UNIT_SUMMONER:
+ Type[i] = TARGET_TYPE_UNIT_CASTER;
+ break;
+ case TARGET_UNIT_TARGET_MINIPET:
+ case TARGET_UNIT_TARGET_ALLY:
+ case TARGET_UNIT_TARGET_RAID:
+ case TARGET_UNIT_TARGET_ANY:
+ case TARGET_UNIT_TARGET_ENEMY:
+ case TARGET_UNIT_TARGET_PARTY:
+ case TARGET_UNIT_TARGET_PASSENGER:
+ case TARGET_UNIT_TARGET_ALLY_PARTY:
+ case TARGET_UNIT_TARGET_CLASS_RAID:
+ case TARGET_UNIT_CHAINHEAL:
+ Type[i] = TARGET_TYPE_UNIT_TARGET;
+ break;
+ case TARGET_UNIT_NEARBY_ENEMY:
+ case TARGET_UNIT_NEARBY_ALLY:
+ case TARGET_UNIT_NEARBY_ENTRY:
+ case TARGET_UNIT_NEARBY_PARTY:
+ case TARGET_UNIT_NEARBY_RAID:
+ case TARGET_GAMEOBJECT_NEARBY_ENTRY:
+ Type[i] = TARGET_TYPE_UNIT_NEARBY;
+ break;
+ case TARGET_UNIT_AREA_ENEMY_SRC:
+ case TARGET_UNIT_AREA_ALLY_SRC:
+ case TARGET_UNIT_AREA_ENTRY_SRC:
+ case TARGET_UNIT_AREA_PARTY_SRC:
+ case TARGET_GAMEOBJECT_AREA_SRC:
+ Type[i] = TARGET_TYPE_AREA_SRC;
+ break;
+ case TARGET_UNIT_AREA_ENEMY_DST:
+ case TARGET_UNIT_AREA_ALLY_DST:
+ case TARGET_UNIT_AREA_ENTRY_DST:
+ case TARGET_UNIT_AREA_PARTY_DST:
+ case TARGET_GAMEOBJECT_AREA_DST:
+ Type[i] = TARGET_TYPE_AREA_DST;
+ break;
+ case TARGET_UNIT_CONE_ENEMY:
+ case TARGET_UNIT_CONE_ALLY:
+ case TARGET_UNIT_CONE_ENTRY:
+ case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
+ case TARGET_UNIT_AREA_PATH:
+ case TARGET_GAMEOBJECT_AREA_PATH:
+ Type[i] = TARGET_TYPE_AREA_CONE;
+ break;
+ case TARGET_DST_CASTER:
+ case TARGET_SRC_CASTER:
+ case TARGET_MINION:
+ case TARGET_DEST_CASTER_FRONT_LEAP:
+ case TARGET_DEST_CASTER_FRONT:
+ case TARGET_DEST_CASTER_BACK:
+ case TARGET_DEST_CASTER_RIGHT:
+ case TARGET_DEST_CASTER_LEFT:
+ case TARGET_DEST_CASTER_FRONT_LEFT:
+ case TARGET_DEST_CASTER_BACK_LEFT:
+ case TARGET_DEST_CASTER_BACK_RIGHT:
+ case TARGET_DEST_CASTER_FRONT_RIGHT:
+ case TARGET_DEST_CASTER_RANDOM:
+ case TARGET_DEST_CASTER_RADIUS:
+ Type[i] = TARGET_TYPE_DEST_CASTER;
+ break;
+ case TARGET_DST_TARGET_ENEMY:
+ case TARGET_DEST_TARGET_ANY:
+ case TARGET_DEST_TARGET_FRONT:
+ case TARGET_DEST_TARGET_BACK:
+ case TARGET_DEST_TARGET_RIGHT:
+ case TARGET_DEST_TARGET_LEFT:
+ case TARGET_DEST_TARGET_FRONT_LEFT:
+ case TARGET_DEST_TARGET_BACK_LEFT:
+ case TARGET_DEST_TARGET_BACK_RIGHT:
+ case TARGET_DEST_TARGET_FRONT_RIGHT:
+ case TARGET_DEST_TARGET_RANDOM:
+ case TARGET_DEST_TARGET_RADIUS:
+ Type[i] = TARGET_TYPE_DEST_TARGET;
+ break;
+ case TARGET_DEST_DYNOBJ_ENEMY:
+ case TARGET_DEST_DYNOBJ_ALLY:
+ case TARGET_DEST_DYNOBJ_NONE:
+ case TARGET_DEST_DEST:
+ case TARGET_DEST_TRAJ:
+ case TARGET_DEST_DEST_FRONT_LEFT:
+ case TARGET_DEST_DEST_BACK_LEFT:
+ case TARGET_DEST_DEST_BACK_RIGHT:
+ case TARGET_DEST_DEST_FRONT_RIGHT:
+ case TARGET_DEST_DEST_FRONT:
+ case TARGET_DEST_DEST_BACK:
+ case TARGET_DEST_DEST_RIGHT:
+ case TARGET_DEST_DEST_LEFT:
+ case TARGET_DEST_DEST_RANDOM:
+ case TARGET_DEST_DEST_RANDOM_DIR_DIST:
+ Type[i] = TARGET_TYPE_DEST_DEST;
+ break;
+ case TARGET_DST_DB:
+ case TARGET_DST_HOME:
+ case TARGET_DST_NEARBY_ENTRY:
+ Type[i] = TARGET_TYPE_DEST_SPECIAL;
+ break;
+ case TARGET_UNIT_CHANNEL_TARGET:
+ case TARGET_DEST_CHANNEL_TARGET:
+ case TARGET_DEST_CHANNEL_CASTER:
+ Type[i] = TARGET_TYPE_CHANNEL;
+ break;
+ default:
+ Type[i] = TARGET_TYPE_DEFAULT;
+ }
+ }
+}
+
+bool SpellImplicitTargetInfo::Init = SpellImplicitTargetInfo::InitStaticData();
+bool SpellImplicitTargetInfo::Area[TOTAL_SPELL_TARGETS];
+SpellSelectTargetTypes SpellImplicitTargetInfo::Type[TOTAL_SPELL_TARGETS];
+
+SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
+{
+ _spellInfo = spellInfo;
+ _effIndex = effIndex;
+ Effect = spellEntry->Effect[effIndex];
+ ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex];
+ Amplitude = spellEntry->EffectAmplitude[effIndex];
+ DieSides = spellEntry->EffectDieSides[effIndex];
+ RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex];
+ BasePoints = spellEntry->EffectBasePoints[effIndex];
+ PointsPerComboPoint = spellEntry->EffectPointsPerComboPoint[effIndex];
+ ValueMultiplier = spellEntry->EffectValueMultiplier[effIndex];
+ DamageMultiplier = spellEntry->EffectDamageMultiplier[effIndex];
+ BonusMultiplier = spellEntry->EffectBonusMultiplier[effIndex];
+ MiscValue = spellEntry->EffectMiscValue[effIndex];
+ MiscValueB = spellEntry->EffectMiscValueB[effIndex];
+ Mechanic = Mechanics(spellEntry->EffectMechanic[effIndex]);
+ TargetA = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetA[effIndex]);
+ TargetB = SpellImplicitTargetInfo(spellEntry->EffectImplicitTargetB[effIndex]);
+ RadiusEntry = spellEntry->EffectRadiusIndex[effIndex] ? sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[effIndex]) : NULL;
+ ChainTarget = spellEntry->EffectChainTarget[effIndex];
+ ItemType = spellEntry->EffectItemType[effIndex];
+ TriggerSpell = spellEntry->EffectTriggerSpell[effIndex];
+ SpellClassMask = spellEntry->EffectSpellClassMask[effIndex];
+}
+
+bool SpellEffectInfo::IsEffect() const
+{
+ return Effect != 0;
+}
+
+bool SpellEffectInfo::IsEffect(SpellEffects effectName) const
+{
+ return Effect == effectName;
+}
+
+bool SpellEffectInfo::IsAura() const
+{
+ return (IsUnitOwnedAuraEffect() || Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) && ApplyAuraName != 0;
+}
+
+bool SpellEffectInfo::IsAura(AuraType aura) const
+{
+ return IsAura() && ApplyAuraName == aura;
+}
+
+bool SpellEffectInfo::IsArea() const
+{
+ return TargetA.IsArea() || TargetB.IsArea();
+}
+
+bool SpellEffectInfo::IsAreaAuraEffect() const
+{
+ if (Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY ||
+ Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID ||
+ Effect == SPELL_EFFECT_APPLY_AREA_AURA_FRIEND ||
+ Effect == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY ||
+ Effect == SPELL_EFFECT_APPLY_AREA_AURA_PET ||
+ Effect == SPELL_EFFECT_APPLY_AREA_AURA_OWNER)
+ return true;
+ return false;
+}
+
+bool SpellEffectInfo::IsFarUnitTargetEffect() const
+{
+ return (Effect == SPELL_EFFECT_SUMMON_PLAYER);
+}
+
+bool SpellEffectInfo::IsFarDestTargetEffect() const
+{
+ return (Effect == SPELL_EFFECT_TELEPORT_UNITS);
+}
+
+bool SpellEffectInfo::IsUnitOwnedAuraEffect() const
+{
+ return (IsAreaAuraEffect() || Effect == SPELL_EFFECT_APPLY_AURA);
+}
+
+int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const* /*target*/) const
+{
+ float basePointsPerLevel = RealPointsPerLevel;
+ int32 basePoints = bp ? *bp : BasePoints;
+ int32 randomPoints = int32(DieSides);
+
+ // base amount modification based on spell lvl vs caster lvl
+ if (caster)
+ {
+ int32 level = int32(caster->getLevel());
+ if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
+ level = int32(_spellInfo->MaxLevel);
+ else if (level < int32(_spellInfo->BaseLevel))
+ level = int32(_spellInfo->BaseLevel);
+ level -= int32(_spellInfo->SpellLevel);
+ basePoints += int32(level * basePointsPerLevel);
+ }
+
+ // roll in a range <1;EffectDieSides> as of patch 3.3.3
+ switch (randomPoints)
+ {
+ case 0: break;
+ case 1: basePoints += 1; break; // range 1..1
+ default:
+ // range can have positive (1..rand) and negative (rand..1) values, so order its for irand
+ int32 randvalue = (randomPoints >= 1)
+ ? irand(1, randomPoints)
+ : irand(randomPoints, 1);
+
+ basePoints += randvalue;
+ break;
+ }
+
+ float value = float(basePoints);
+
+ // random damage
+ if (caster)
+ {
+ // bonus amount from combo points
+ if (caster->m_movedPlayer)
+ if (uint8 comboPoints = caster->m_movedPlayer->GetComboPoints())
+ if (float comboDamage = PointsPerComboPoint)
+ value += comboDamage * comboPoints;
+
+ value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
+
+ // amount multiplication based on caster's level
+ if (!basePointsPerLevel && (_spellInfo->Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION && _spellInfo->SpellLevel) &&
+ Effect != SPELL_EFFECT_WEAPON_PERCENT_DAMAGE &&
+ Effect != SPELL_EFFECT_KNOCK_BACK &&
+ ApplyAuraName != SPELL_AURA_MOD_SPEED_ALWAYS &&
+ ApplyAuraName != SPELL_AURA_MOD_SPEED_NOT_STACK &&
+ ApplyAuraName != SPELL_AURA_MOD_INCREASE_SPEED &&
+ ApplyAuraName != SPELL_AURA_MOD_DECREASE_SPEED)
+ //there are many more: slow speed, -healing pct
+ value *= 0.25f * exp(caster->getLevel() * (70 - _spellInfo->SpellLevel) / 1000.0f);
+ //value = int32(value * (int32)getLevel() / (int32)(_spellInfo->spellLevel ? _spellInfo->spellLevel : 1));
+ }
+
+ return int32(value);
+}
+
+int32 SpellEffectInfo::CalcBaseValue(int32 value) const
+{
+ if (DieSides == 0)
+ return value;
+ else
+ return value - 1;
+}
+
+float SpellEffectInfo::CalcValueMultiplier(Unit* caster, Spell* spell) const
+{
+ float multiplier = ValueMultiplier;
+ if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
+ modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_VALUE_MULTIPLIER, multiplier, spell);
+ return multiplier;
+}
+
+float SpellEffectInfo::CalcDamageMultiplier(Unit* caster, Spell* spell) const
+{
+ float multiplier = DamageMultiplier;
+ if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
+ modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_DAMAGE_MULTIPLIER, multiplier, spell);
+ return multiplier;
+}
+
+bool SpellEffectInfo::HasRadius() const
+{
+ return RadiusEntry != NULL;
+}
+
+float SpellEffectInfo::CalcRadius(Unit* caster, Spell* spell) const
+{
+ float radius = RadiusEntry->radiusMax;
+ if (Player* modOwner = (caster ? caster->GetSpellModOwner() : NULL))
+ modOwner->ApplySpellMod(_spellInfo->Id, SPELLMOD_RADIUS, radius, spell);
+ return radius;
+}
+
+SpellEffectTargetTypes SpellEffectInfo::GetRequiredTargetType() const
+{
+ return RequiredTargetType[Effect];
+}
+
+bool SpellEffectInfo::InitStaticData()
+{
+ InitRequiredTargetTypeData();
+ return true;
+}
+
+void SpellEffectInfo::InitRequiredTargetTypeData()
+{
+ for (uint8 i = 0; i < TOTAL_SPELL_EFFECTS; ++i)
+ {
+ switch (i)
+ {
+ case SPELL_EFFECT_PERSISTENT_AREA_AURA: //27
+ case SPELL_EFFECT_SUMMON: //28
+ case SPELL_EFFECT_TRIGGER_MISSILE: //32
+ case SPELL_EFFECT_TRANS_DOOR: //50 summon object
+ case SPELL_EFFECT_SUMMON_PET: //56
+ case SPELL_EFFECT_ADD_FARSIGHT: //72
+ case SPELL_EFFECT_SUMMON_OBJECT_WILD: //76
+ //case SPELL_EFFECT_SUMMON_CRITTER: //97 not 303
+ case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: //104
+ case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: //105
+ case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: //106
+ case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: //107
+ case SPELL_EFFECT_SUMMON_DEAD_PET: //109
+ case SPELL_EFFECT_TRIGGER_SPELL_2: //151 ritual of summon
+ RequiredTargetType[i] = SPELL_REQUIRE_DEST;
+ break;
+ case SPELL_EFFECT_PARRY: // 0
+ case SPELL_EFFECT_BLOCK: // 0
+ case SPELL_EFFECT_SKILL: // always with dummy 3 as A
+ //case SPELL_EFFECT_LEARN_SPELL: // 0 may be 5 pet
+ case SPELL_EFFECT_TRADE_SKILL: // 0 or 1
+ case SPELL_EFFECT_PROFICIENCY: // 0
+ RequiredTargetType[i] = SPELL_REQUIRE_NONE;
+ break;
+ case SPELL_EFFECT_ENCHANT_ITEM:
+ case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
+ case SPELL_EFFECT_DISENCHANT:
+ //in 243 this is 0, in 309 it is 1
+ //so both item target and unit target is pushed, and cause crash
+ //case SPELL_EFFECT_FEED_PET:
+ case SPELL_EFFECT_PROSPECTING:
+ case SPELL_EFFECT_MILLING:
+ case SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC:
+ RequiredTargetType[i] = SPELL_REQUIRE_ITEM;
+ break;
+ //caster must be pushed otherwise no sound
+ case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
+ case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
+ case SPELL_EFFECT_APPLY_AREA_AURA_PET:
+ case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
+ case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
+ case SPELL_EFFECT_CHARGE:
+ case SPELL_EFFECT_CHARGE_DEST:
+ case SPELL_EFFECT_JUMP:
+ case SPELL_EFFECT_JUMP_DEST:
+ case SPELL_EFFECT_LEAP_BACK:
+ RequiredTargetType[i] = SPELL_REQUIRE_CASTER;
+ break;
+ //case SPELL_EFFECT_WMO_DAMAGE:
+ //case SPELL_EFFECT_WMO_REPAIR:
+ //case SPELL_EFFECT_WMO_CHANGE:
+ // RequiredTargetType[i] = SPELL_REQUIRE_GOBJECT;
+ // break;
+ default:
+ RequiredTargetType[i] = SPELL_REQUIRE_UNIT;
+ break;
+ }
+ }
+}
+
+bool SpellEffectInfo::Init = SpellEffectInfo::InitStaticData();
+SpellEffectTargetTypes SpellEffectInfo::RequiredTargetType[TOTAL_SPELL_EFFECTS];
+
+SpellInfo::SpellInfo(SpellEntry const* spellEntry)
+{
+ Id = spellEntry->Id;
+ Category = spellEntry->Category;
+ Dispel = spellEntry->Dispel;
+ Mechanic = spellEntry->Mechanic;
+ Attributes = spellEntry->Attributes;
+ AttributesEx = spellEntry->AttributesEx;
+ AttributesEx2 = spellEntry->AttributesEx2;
+ AttributesEx3 = spellEntry->AttributesEx3;
+ AttributesEx4 = spellEntry->AttributesEx4;
+ AttributesEx5 = spellEntry->AttributesEx5;
+ AttributesEx6 = spellEntry->AttributesEx6;
+ AttributesEx7 = spellEntry->AttributesEx7;
+ AttributesCu = 0;
+ Stances = spellEntry->Stances;
+ StancesNot = spellEntry->StancesNot;
+ Targets = spellEntry->Targets;
+ TargetCreatureType = spellEntry->TargetCreatureType;
+ RequiresSpellFocus = spellEntry->RequiresSpellFocus;
+ FacingCasterFlags = spellEntry->FacingCasterFlags;
+ CasterAuraState = spellEntry->CasterAuraState;
+ TargetAuraState = spellEntry->TargetAuraState;
+ CasterAuraStateNot = spellEntry->CasterAuraStateNot;
+ TargetAuraStateNot = spellEntry->TargetAuraStateNot;
+ CasterAuraSpell = spellEntry->casterAuraSpell;
+ TargetAuraSpell = spellEntry->targetAuraSpell;
+ ExcludeCasterAuraSpell = spellEntry->excludeCasterAuraSpell;
+ ExcludeTargetAuraSpell = spellEntry->excludeTargetAuraSpell;
+ CastTimeEntry = spellEntry->CastingTimeIndex ? sSpellCastTimesStore.LookupEntry(spellEntry->CastingTimeIndex) : NULL;
+ RecoveryTime = spellEntry->RecoveryTime;
+ CategoryRecoveryTime = spellEntry->CategoryRecoveryTime;
+ StartRecoveryCategory = spellEntry->StartRecoveryCategory;
+ StartRecoveryTime = spellEntry->StartRecoveryTime;
+ InterruptFlags = spellEntry->InterruptFlags;
+ AuraInterruptFlags = spellEntry->AuraInterruptFlags;
+ ChannelInterruptFlags = spellEntry->ChannelInterruptFlags;
+ ProcFlags = spellEntry->procFlags;
+ ProcChance = spellEntry->procChance;
+ ProcCharges = spellEntry->procCharges;
+ MaxLevel = spellEntry->maxLevel;
+ BaseLevel = spellEntry->baseLevel;
+ SpellLevel = spellEntry->spellLevel;
+ DurationEntry = spellEntry->DurationIndex ? sSpellDurationStore.LookupEntry(spellEntry->DurationIndex) : NULL;
+ PowerType = spellEntry->powerType;
+ ManaCost = spellEntry->manaCost;
+ ManaCostPerlevel = spellEntry->manaCostPerlevel;
+ ManaPerSecond = spellEntry->manaPerSecond;
+ ManaPerSecondPerLevel = spellEntry->manaPerSecondPerLevel;
+ ManaCostPercentage = spellEntry->ManaCostPercentage;
+ RuneCostID = spellEntry->runeCostID;
+ RangeEntry = spellEntry->rangeIndex ? sSpellRangeStore.LookupEntry(spellEntry->rangeIndex) : NULL;
+ Speed = spellEntry->speed;
+ StackAmount = spellEntry->StackAmount;
+ for (uint8 i = 0; i < 2; ++i)
+ Totem[i] = spellEntry->Totem[i];
+ for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i)
+ Reagent[i] = spellEntry->Reagent[i];
+ for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i)
+ ReagentCount[i] = spellEntry->ReagentCount[i];
+ EquippedItemClass = spellEntry->EquippedItemClass;
+ EquippedItemSubClassMask = spellEntry->EquippedItemSubClassMask;
+ EquippedItemInventoryTypeMask = spellEntry->EquippedItemInventoryTypeMask;
+ for (uint8 i = 0; i < 2; ++i)
+ TotemCategory[i] = spellEntry->TotemCategory[i];
+ for (uint8 i = 0; i < 2; ++i)
+ SpellVisual[i] = spellEntry->SpellVisual[i];
+ SpellIconID = spellEntry->SpellIconID;
+ ActiveIconID = spellEntry->activeIconID;
+ for (uint8 i = 0; i < 16; ++i)
+ SpellName[i] = spellEntry->SpellName[i];
+ for (uint8 i = 0; i < 16; ++i)
+ Rank[i] = spellEntry->Rank[i];
+ MaxTargetLevel = spellEntry->MaxTargetLevel;
+ MaxAffectedTargets = spellEntry->MaxAffectedTargets;
+ SpellFamilyName = spellEntry->SpellFamilyName;
+ SpellFamilyFlags = spellEntry->SpellFamilyFlags;
+ DmgClass = spellEntry->DmgClass;
+ PreventionType = spellEntry->PreventionType;
+ AreaGroupId = spellEntry->AreaGroupId;
+ SchoolMask = spellEntry->SchoolMask;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ Effects[i] = SpellEffectInfo(spellEntry, this, i);
+ ChainEntry = NULL;
+}
+
+bool SpellInfo::HasEffect(SpellEffects effect) const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].IsEffect(effect))
+ return true;
+ return false;
+}
+
+bool SpellInfo::HasAura(AuraType aura) const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].IsAura(aura))
+ return true;
+ return false;
+}
+
+bool SpellInfo::HasAreaAuraEffect() const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].IsAreaAuraEffect())
+ return true;
+ return false;
+}
+
+bool SpellInfo::IsExplicitDiscovery() const
+{
+ return ((Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM
+ || Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2)
+ && Effects[1].Effect == SPELL_EFFECT_SCRIPT_EFFECT)
+ || Id == 64323;
+}
+
+bool SpellInfo::IsLootCrafting() const
+{
+ return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM ||
+ // different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item
+ (Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 &&
+ (TotemCategory[0] != 0 || Effects[0].ItemType == 0)));
+}
+
+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
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = Effects[i].MiscValue;
+
+ if (IsProfessionOrRidingSkill(skill))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SpellInfo::IsProfession() const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = Effects[i].MiscValue;
+
+ if (IsProfessionSkill(skill))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SpellInfo::IsPrimaryProfession() const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect == SPELL_EFFECT_SKILL)
+ {
+ uint32 skill = Effects[i].MiscValue;
+
+ if (IsPrimaryProfessionSkill(skill))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SpellInfo::IsPrimaryProfessionFirstRank() const
+{
+ return IsPrimaryProfession() && GetRank() == 1;
+}
+
+bool SpellInfo::IsAbilityLearnedWithProfession() const
+{
+ SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
+
+ for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
+ {
+ SkillLineAbilityEntry const* pAbility = _spell_idx->second;
+ if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
+ continue;
+
+ if (pAbility->req_skill_value > 0)
+ return true;
+ }
+
+ return false;
+}
+
+bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const
+{
+ SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
+
+ for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
+ if (_spell_idx->second->skillId == uint32(skillType))
+ return true;
+
+ return false;
+}
+
+bool SpellInfo::IsAOE() const
+{
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].IsArea())
+ return true;
+ return false;
+}
+
+bool SpellInfo::IsRequiringSelectedTarget() const
+{
+ for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].TargetA.GetType() == TARGET_TYPE_UNIT_TARGET
+ || Effects[i].TargetB.GetType() == TARGET_TYPE_UNIT_TARGET
+ || Effects[i].TargetA.GetType() == TARGET_TYPE_CHANNEL
+ || Effects[i].TargetB.GetType() == TARGET_TYPE_CHANNEL
+ || Effects[i].TargetA.GetType() == TARGET_TYPE_DEST_TARGET
+ || Effects[i].TargetB.GetType() == TARGET_TYPE_DEST_TARGET)
+ return true;
+ }
+ return false;
+}
+
+bool SpellInfo::IsPassive() const
+{
+ return Attributes & SPELL_ATTR0_PASSIVE;
+}
+
+bool SpellInfo::IsAutocastable() const
+{
+ if (Attributes & SPELL_ATTR0_PASSIVE)
+ return false;
+ if (AttributesEx & SPELL_ATTR1_UNAUTOCASTABLE_BY_PET)
+ return false;
+ return true;
+}
+
+bool SpellInfo::IsStackableWithRanks() const
+{
+ if (IsPassive())
+ return false;
+ if (PowerType != POWER_MANA && PowerType != POWER_HEALTH)
+ return false;
+ if (IsProfessionOrRiding())
+ return false;
+
+ if (IsAbilityLearnedWithProfession())
+ return false;
+
+ // All stance spells. if any better way, change it.
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_PALADIN:
+ // Paladin aura Spell
+ if (Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID)
+ return false;
+ break;
+ case SPELLFAMILY_DRUID:
+ // Druid form Spell
+ if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA &&
+ Effects[i].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
+ return false;
+ break;
+ case SPELLFAMILY_ROGUE:
+ // Rogue Stealth
+ if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA &&
+ Effects[i].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT)
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SpellInfo::IsPassiveStackableWithRanks() const
+{
+ return IsPassive() && !HasEffect(SPELL_EFFECT_APPLY_AURA);
+}
+
+bool SpellInfo::IsMultiSlotAura() const
+{
+ return IsPassive() || Id == 44413;
+}
+
+bool SpellInfo::IsDeathPersistent() const
+{
+ return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT;
+}
+
+bool SpellInfo::IsRequiringDeadTarget() const
+{
+ return AttributesEx3 & SPELL_ATTR3_REQUIRE_DEAD_TARGET;
+}
+
+bool SpellInfo::IsAllowingDeadTarget() const
+{
+ return AttributesEx2 & SPELL_ATTR2_ALLOW_DEAD_TARGET;
+}
+
+bool SpellInfo::CanBeUsedInCombat() const
+{
+ return !(Attributes & SPELL_ATTR0_CANT_USED_IN_COMBAT);
+}
+
+bool SpellInfo::IsPositive() const
+{
+ return AttributesCu & SPELL_ATTR0_CU_NEGATIVE;
+}
+
+bool SpellInfo::IsPositiveEffect(uint8 effIndex) const
+{
+ switch (effIndex)
+ {
+ default:
+ case 0:
+ return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF0);
+ case 1:
+ return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF1);
+ case 2:
+ return !(AttributesCu & SPELL_ATTR0_CU_NEGATIVE_EFF2);
+ }
+}
+
+bool SpellInfo::IsChanneled() const
+{
+ return (AttributesEx & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2));
+}
+
+bool SpellInfo::NeedsComboPoints() const
+{
+ return (AttributesEx & (SPELL_ATTR1_REQ_COMBO_POINTS1 | SPELL_ATTR1_REQ_COMBO_POINTS2));
+}
+
+bool SpellInfo::IsBreakingStealth() const
+{
+ return !(AttributesEx & SPELL_ATTR1_NOT_BREAK_STEALTH);
+}
+
+bool SpellInfo::IsRangedWeaponSpell() const
+{
+ return (SpellFamilyName == SPELLFAMILY_HUNTER && !(SpellFamilyFlags[1] & 0x10000000)) // for 53352, cannot find better way
+ || (EquippedItemSubClassMask & ITEM_SUBCLASS_MASK_WEAPON_RANGED);
+}
+
+bool SpellInfo::IsAutoRepeatRangedSpell() const
+{
+ return AttributesEx2 & SPELL_ATTR2_AUTOREPEAT_FLAG;
+}
+
+bool SpellInfo::IsAffectedBySpellMod(SpellModifier* mod) const
+{
+ SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId);
+ // False if affect_spell == NULL or spellFamily not equal
+ if (!affectSpell || affectSpell->SpellFamilyName != SpellFamilyName)
+ return false;
+
+ // true
+ if (mod->mask & SpellFamilyFlags)
+ return true;
+
+ return false;
+}
+
+bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const
+{
+ // these spells pierce all avalible spells (Resurrection Sickness for example)
+ if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ return true;
+
+ // these spells (Cyclone for example) can pierce all...
+ if ((AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)
+ // ...but not these (Divine shield for example)
+ && !(aura && (aura->Mechanic == MECHANIC_IMMUNE_SHIELD || aura->Mechanic == MECHANIC_INVULNERABILITY)))
+ return true;
+
+ return false;
+}
+
+bool SpellInfo::CanDispelAura(SpellInfo const* aura) const
+{
+ // These auras (like ressurection sickness) can't be dispelled
+ if (aura->Attributes & SPELL_ATTR0_NEGATIVE_1)
+ return false;
+
+ // These spells (like Mass Dispel) can dispell all auras
+ if (Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ return true;
+
+ // These auras (like Divine Shield) can't be dispelled
+ if (aura->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)
+ return false;
+
+ // These auras (Cyclone for example) are not dispelable
+ if (aura->AttributesEx & SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE)
+ return false;
+
+ return true;
+}
+
+bool SpellInfo::IsSingleTarget() const
+{
+ // all other single target spells have if it has AttributesEx5
+ if (AttributesEx5 & SPELL_ATTR5_SINGLE_TARGET_SPELL)
+ return true;
+
+ switch (GetSpellSpecific())
+ {
+ case SPELL_SPECIFIC_JUDGEMENT:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool SpellInfo::IsSingleTargetWith(SpellInfo const* spellInfo) const
+{
+ // TODO - need better check
+ // Equal icon and spellfamily
+ if (SpellFamilyName == spellInfo->SpellFamilyName &&
+ SpellIconID == spellInfo->SpellIconID)
+ return true;
+
+ SpellSpecificType spec = GetSpellSpecific();
+ // spell with single target specific types
+ switch (spec)
+ {
+ case SPELL_SPECIFIC_JUDGEMENT:
+ case SPELL_SPECIFIC_MAGE_POLYMORPH:
+ if (spellInfo->GetSpellSpecific() == spec)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool SpellInfo::IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const
+{
+ SpellSpecificType spellSpec = GetSpellSpecific();
+ switch (spellSpec)
+ {
+ case SPELL_SPECIFIC_SEAL:
+ case SPELL_SPECIFIC_HAND:
+ case SPELL_SPECIFIC_AURA:
+ case SPELL_SPECIFIC_STING:
+ case SPELL_SPECIFIC_CURSE:
+ case SPELL_SPECIFIC_ASPECT:
+ case SPELL_SPECIFIC_JUDGEMENT:
+ case SPELL_SPECIFIC_WARLOCK_CORRUPTION:
+ return spellSpec == spellInfo->GetSpellSpecific();
+ default:
+ return false;
+ }
+}
+
+bool SpellInfo::IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const
+{
+ SpellSpecificType spellSpec1 = GetSpellSpecific();
+ SpellSpecificType spellSpec2 = spellInfo->GetSpellSpecific();
+ switch (spellSpec1)
+ {
+ case SPELL_SPECIFIC_PHASE:
+ case SPELL_SPECIFIC_TRACKER:
+ case SPELL_SPECIFIC_WARLOCK_ARMOR:
+ case SPELL_SPECIFIC_MAGE_ARMOR:
+ case SPELL_SPECIFIC_ELEMENTAL_SHIELD:
+ case SPELL_SPECIFIC_MAGE_POLYMORPH:
+ case SPELL_SPECIFIC_PRESENCE:
+ case SPELL_SPECIFIC_CHARM:
+ case SPELL_SPECIFIC_SCROLL:
+ case SPELL_SPECIFIC_WARRIOR_ENRAGE:
+ case SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE:
+ case SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT:
+ return spellSpec1 == spellSpec2;
+ case SPELL_SPECIFIC_FOOD:
+ return spellSpec2 == SPELL_SPECIFIC_FOOD
+ || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK;
+ case SPELL_SPECIFIC_DRINK:
+ return spellSpec2 == SPELL_SPECIFIC_DRINK
+ || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK;
+ case SPELL_SPECIFIC_FOOD_AND_DRINK:
+ return spellSpec2 == SPELL_SPECIFIC_FOOD
+ || spellSpec2 == SPELL_SPECIFIC_DRINK
+ || spellSpec2 == SPELL_SPECIFIC_FOOD_AND_DRINK;
+ default:
+ return false;
+ }
+}
+
+SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
+{
+ // talents that learn spells can have stance requirements that need ignore
+ // (this requirement only for client-side stance show in talent description)
+ if (GetTalentSpellCost(Id) > 0 &&
+ (Effects[0].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[1].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[2].Effect == SPELL_EFFECT_LEARN_SPELL))
+ return SPELL_CAST_OK;
+
+ uint32 stanceMask = (form ? 1 << (form - 1) : 0);
+
+ if (stanceMask & StancesNot) // can explicitly not be casted in this stance
+ return SPELL_FAILED_NOT_SHAPESHIFT;
+
+ if (stanceMask & Stances) // can explicitly be casted in this stance
+ return SPELL_CAST_OK;
+
+ bool actAsShifted = false;
+ SpellShapeshiftEntry const* shapeInfo = NULL;
+ if (form > 0)
+ {
+ shapeInfo = sSpellShapeshiftStore.LookupEntry(form);
+ if (!shapeInfo)
+ {
+ sLog->outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form);
+ return SPELL_CAST_OK;
+ }
+ actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells
+ }
+
+ if (actAsShifted)
+ {
+ if (Attributes & SPELL_ATTR0_NOT_SHAPESHIFT) // not while shapeshifted
+ return SPELL_FAILED_NOT_SHAPESHIFT;
+ else if (Stances != 0) // needs other shapeshift
+ return SPELL_FAILED_ONLY_SHAPESHIFT;
+ }
+ else
+ {
+ // needs shapeshift
+ if (!(AttributesEx2 & SPELL_ATTR2_NOT_NEED_SHAPESHIFT) && Stances != 0)
+ return SPELL_FAILED_ONLY_SHAPESHIFT;
+ }
+
+ // Check if stance disables cast of not-stance spells
+ // Example: cannot cast any other spells in zombie or ghoul form
+ // TODO: Find a way to disable use of these spells clientside
+ if (shapeInfo && shapeInfo->flags1 & 0x400)
+ {
+ if (!(stanceMask & Stances))
+ return SPELL_FAILED_ONLY_SHAPESHIFT;
+ }
+
+ return SPELL_CAST_OK;
+}
+
+SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) const
+{
+ // normal case
+ if (AreaGroupId > 0)
+ {
+ bool found = false;
+ AreaGroupEntry const* groupEntry = sAreaGroupStore.LookupEntry(AreaGroupId);
+ while (groupEntry)
+ {
+ for (uint8 i = 0; i < MAX_GROUP_AREA_IDS; ++i)
+ if (groupEntry->AreaId[i] == zone_id || groupEntry->AreaId[i] == area_id)
+ found = true;
+ if (found || !groupEntry->nextGroup)
+ break;
+ // Try search in next group
+ groupEntry = sAreaGroupStore.LookupEntry(groupEntry->nextGroup);
+ }
+
+ if (!found)
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+
+ // continent limitation (virtual continent)
+ if (AttributesEx4 & SPELL_ATTR4_CAST_ONLY_IN_OUTLAND)
+ {
+ uint32 v_map = GetVirtualMapForMapAndZone(map_id, zone_id);
+ MapEntry const* mapEntry = sMapStore.LookupEntry(v_map);
+ if (!mapEntry || mapEntry->addon < 1 || !mapEntry->IsContinent())
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+
+ // raid instance limitation
+ if (AttributesEx6 & SPELL_ATTR6_NOT_IN_RAID_INSTANCE)
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry || mapEntry->IsRaid())
+ return SPELL_FAILED_NOT_IN_RAID_INSTANCE;
+ }
+
+ // DB base check (if non empty then must fit at least single for allow)
+ SpellAreaMapBounds saBounds = sSpellMgr->GetSpellAreaMapBounds(Id);
+ if (saBounds.first != saBounds.second)
+ {
+ for (SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
+ {
+ if (itr->second.IsFitToRequirements(player, zone_id, area_id))
+ return SPELL_CAST_OK;
+ }
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+
+ // bg spell checks
+ switch (Id)
+ {
+ case 23333: // Warsong Flag
+ case 23335: // Silverwing Flag
+ return map_id == 489 && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ case 34976: // Netherstorm Flag
+ return map_id == 566 && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ case 2584: // Waiting to Resurrect
+ case 22011: // Spirit Heal Channel
+ case 22012: // Spirit Heal
+ case 24171: // Resurrection Impact Visual
+ case 42792: // Recently Dropped Flag
+ case 43681: // Inactive
+ case 44535: // Spirit Heal (mana)
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ return zone_id == 4197 || (mapEntry->IsBattleground() && player && player->InBattleground()) ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ case 44521: // Preparation
+ {
+ if (!player)
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ if (!mapEntry->IsBattleground())
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ Battleground* bg = player->GetBattleground();
+ return bg && bg->GetStatus() == STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ case 32724: // Gold Team (Alliance)
+ case 32725: // Green Team (Alliance)
+ case 35774: // Gold Team (Horde)
+ case 35775: // Green Team (Horde)
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ return mapEntry->IsBattleArena() && player && player->InBattleground() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ case 32727: // Arena Preparation
+ {
+ if (!player)
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
+ if (!mapEntry)
+ return SPELL_FAILED_INCORRECT_AREA;
+
+ if (!mapEntry->IsBattleArena())
+ return SPELL_FAILED_REQUIRES_AREA;
+
+ Battleground* bg = player->GetBattleground();
+ return bg && bg->GetStatus() == STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA;
+ }
+ }
+
+ // aura limitations
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ switch (Effects[i].ApplyAuraName)
+ {
+ case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED:
+ case SPELL_AURA_FLY:
+ {
+ if (player && !player->IsKnowHowFlyIn(map_id, zone_id))
+ return SPELL_FAILED_INCORRECT_AREA;
+ }
+ }
+ }
+
+ return SPELL_CAST_OK;
+}
+
+SpellSchoolMask SpellInfo::GetSchoolMask() const
+{
+ return SpellSchoolMask(SchoolMask);
+}
+
+uint32 SpellInfo::GetAllEffectsMechanicMask() const
+{
+ uint32 mask = 0;
+ if (Mechanic)
+ mask |= 1<< Mechanic;
+ for (int i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].Mechanic)
+ mask |= 1<< Effects[i].Mechanic;
+ return mask;
+}
+
+uint32 SpellInfo::GetEffectMechanicMask(uint8 effIndex) const
+{
+ uint32 mask = 0;
+ if (Mechanic)
+ mask |= 1<< Mechanic;
+ if (Effects[effIndex].Mechanic)
+ mask |= 1<< Effects[effIndex].Mechanic;
+ return mask;
+}
+
+Mechanics SpellInfo::GetEffectMechanic(uint8 effIndex) const
+{
+ if (Effects[effIndex].Mechanic)
+ return Mechanics(Effects[effIndex].Mechanic);
+ if (Mechanic)
+ return Mechanics(Mechanic);
+ return MECHANIC_NONE;
+}
+
+uint32 SpellInfo::GetDispelMask() const
+{
+ return SpellInfo::GetDispelMask(DispelType(Dispel));
+}
+
+uint32 SpellInfo::GetDispelMask(DispelType type)
+{
+ // If dispel all
+ if (type == DISPEL_ALL)
+ return DISPEL_ALL_MASK;
+ else
+ return uint32(1 << type);
+}
+
+AuraStateType SpellInfo::GetAuraState() const
+{
+ // Seals
+ if (GetSpellSpecific() == SPELL_SPECIFIC_SEAL)
+ return AURA_STATE_JUDGEMENT;
+
+ // Conflagrate aura state on Immolate and Shadowflame
+ if (SpellFamilyName == SPELLFAMILY_WARLOCK &&
+ // Immolate
+ ((SpellFamilyFlags[0] & 4) ||
+ // Shadowflame
+ (SpellFamilyFlags[2] & 2)))
+ return AURA_STATE_CONFLAGRATE;
+
+ // Faerie Fire (druid versions)
+ if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x400)
+ return AURA_STATE_FAERIE_FIRE;
+
+ // Sting (hunter's pet ability)
+ if (Category == 1133)
+ return AURA_STATE_FAERIE_FIRE;
+
+ // Victorious
+ if (SpellFamilyName == SPELLFAMILY_WARRIOR && SpellFamilyFlags[1] & 0x00040000)
+ return AURA_STATE_WARRIOR_VICTORY_RUSH;
+
+ // Swiftmend state on Regrowth & Rejuvenation
+ if (SpellFamilyName == SPELLFAMILY_DRUID && SpellFamilyFlags[0] & 0x50)
+ return AURA_STATE_SWIFTMEND;
+
+ // Deadly poison aura state
+ if (SpellFamilyName == SPELLFAMILY_ROGUE && SpellFamilyFlags[0] & 0x10000)
+ return AURA_STATE_DEADLY_POISON;
+
+ // Enrage aura state
+ if (Dispel == DISPEL_ENRAGE)
+ return AURA_STATE_ENRAGE;
+
+ // Bleeding aura state
+ if (GetAllEffectsMechanicMask() & 1<<MECHANIC_BLEED)
+ return AURA_STATE_BLEEDING;
+
+ if (GetSchoolMask() & SPELL_SCHOOL_MASK_FROST)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STUN
+ || Effects[i].ApplyAuraName == SPELL_AURA_MOD_ROOT)
+ return AURA_STATE_FROZEN;
+
+ switch (Id)
+ {
+ case 71465: // Divine Surge
+ return AURA_STATE_UNKNOWN22;
+ default:
+ break;
+ }
+
+ return AURA_STATE_NONE;
+}
+
+SpellSpecificType SpellInfo::GetSpellSpecific() const
+{
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ {
+ // Food / Drinks (mostly)
+ if (AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED)
+ {
+ bool food = false;
+ bool drink = false;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ switch (Effects[i].ApplyAuraName)
+ {
+ // Food
+ case SPELL_AURA_MOD_REGEN:
+ case SPELL_AURA_OBS_MOD_HEALTH:
+ food = true;
+ break;
+ // Drink
+ case SPELL_AURA_MOD_POWER_REGEN:
+ case SPELL_AURA_OBS_MOD_POWER:
+ drink = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (food && drink)
+ return SPELL_SPECIFIC_FOOD_AND_DRINK;
+ else if (food)
+ return SPELL_SPECIFIC_FOOD;
+ else if (drink)
+ return SPELL_SPECIFIC_DRINK;
+ }
+ // scrolls effects
+ else
+ {
+ SpellInfo const* firstRankSpellInfo = GetFirstRankSpell();
+ switch (firstRankSpellInfo->Id)
+ {
+ case 8118: // Strength
+ case 8099: // Stamina
+ case 8112: // Spirit
+ case 8096: // Intellect
+ case 8115: // Agility
+ case 8091: // Armor
+ return SPELL_SPECIFIC_SCROLL;
+ case 12880: // Enrage (Enrage)
+ case 57518: // Enrage (Wrecking Crew)
+ return SPELL_SPECIFIC_WARRIOR_ENRAGE;
+ }
+ }
+ break;
+ }
+ case SPELLFAMILY_MAGE:
+ {
+ // family flags 18(Molten), 25(Frost/Ice), 28(Mage)
+ if (SpellFamilyFlags[0] & 0x12040000)
+ return SPELL_SPECIFIC_MAGE_ARMOR;
+
+ // Arcane brillance and Arcane intelect (normal check fails because of flags difference)
+ if (SpellFamilyFlags[0] & 0x400)
+ return SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE;
+
+ if ((SpellFamilyFlags[0] & 0x1000000) && Effects[0].ApplyAuraName == SPELL_AURA_MOD_CONFUSE)
+ return SPELL_SPECIFIC_MAGE_POLYMORPH;
+
+ break;
+ }
+ case SPELLFAMILY_WARRIOR:
+ {
+ if (Id == 12292) // Death Wish
+ return SPELL_SPECIFIC_WARRIOR_ENRAGE;
+
+ break;
+ }
+ case SPELLFAMILY_WARLOCK:
+ {
+ // only warlock curses have this
+ if (Dispel == DISPEL_CURSE)
+ return SPELL_SPECIFIC_CURSE;
+
+ // Warlock (Demon Armor | Demon Skin | Fel Armor)
+ if (SpellFamilyFlags[1] & 0x20000020 || SpellFamilyFlags[2] & 0x00000010)
+ return SPELL_SPECIFIC_WARLOCK_ARMOR;
+
+ //seed of corruption and corruption
+ if (SpellFamilyFlags[1] & 0x10 || SpellFamilyFlags[0] & 0x2)
+ return SPELL_SPECIFIC_WARLOCK_CORRUPTION;
+ break;
+ }
+ case SPELLFAMILY_PRIEST:
+ {
+ // Divine Spirit and Prayer of Spirit
+ if (SpellFamilyFlags[0] & 0x20)
+ return SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT;
+
+ break;
+ }
+ case SPELLFAMILY_HUNTER:
+ {
+ // only hunter stings have this
+ if (Dispel == DISPEL_POISON)
+ return SPELL_SPECIFIC_STING;
+
+ // only hunter aspects have this (but not all aspects in hunter family)
+ if (SpellFamilyFlags.HasFlag(0x00380000, 0x00440000, 0x00001010))
+ return SPELL_SPECIFIC_ASPECT;
+
+ break;
+ }
+ case SPELLFAMILY_PALADIN:
+ {
+ // Collection of all the seal family flags. No other paladin spell has any of those.
+ if (SpellFamilyFlags[1] & 0x26000C00
+ || SpellFamilyFlags[0] & 0x0A000000)
+ return SPELL_SPECIFIC_SEAL;
+
+ if (SpellFamilyFlags[0] & 0x00002190)
+ return SPELL_SPECIFIC_HAND;
+
+ // Judgement of Wisdom, Judgement of Light, Judgement of Justice
+ if (Id == 20184 || Id == 20185 || Id == 20186)
+ return SPELL_SPECIFIC_JUDGEMENT;
+
+ // only paladin auras have this (for palaldin class family)
+ if (SpellFamilyFlags[2] & 0x00000020)
+ return SPELL_SPECIFIC_AURA;
+
+ break;
+ }
+ case SPELLFAMILY_SHAMAN:
+ {
+ // family flags 10 (Lightning), 42 (Earth), 37 (Water), proc shield from T2 8 pieces bonus
+ if (SpellFamilyFlags[1] & 0x420
+ || SpellFamilyFlags[0] & 0x00000400
+ || Id == 23552)
+ return SPELL_SPECIFIC_ELEMENTAL_SHIELD;
+
+ break;
+ }
+ case SPELLFAMILY_DEATHKNIGHT:
+ if (Id == 48266 || Id == 48263 || Id == 48265)
+ return SPELL_SPECIFIC_PRESENCE;
+ break;
+ }
+
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA)
+ {
+ switch (Effects[i].ApplyAuraName)
+ {
+ case SPELL_AURA_MOD_CHARM:
+ case SPELL_AURA_MOD_POSSESS_PET:
+ case SPELL_AURA_MOD_POSSESS:
+ case SPELL_AURA_AOE_CHARM:
+ return SPELL_SPECIFIC_CHARM;
+ case SPELL_AURA_TRACK_CREATURES:
+ case SPELL_AURA_TRACK_RESOURCES:
+ case SPELL_AURA_TRACK_STEALTHED:
+ return SPELL_SPECIFIC_TRACKER;
+ case SPELL_AURA_PHASE:
+ return SPELL_SPECIFIC_PHASE;
+ }
+ }
+ }
+
+ return SPELL_SPECIFIC_NORMAL;
+}
+
+float SpellInfo::GetMinRange(bool positive) const
+{
+ if (!RangeEntry)
+ return 0.0f;
+ if (positive)
+ return RangeEntry->minRangeFriend;
+ return RangeEntry->minRangeHostile;
+}
+
+float SpellInfo::GetMaxRange(bool positive) const
+{
+ if (!RangeEntry)
+ return 0.0f;
+ if (positive)
+ return RangeEntry->maxRangeFriend;
+ return RangeEntry->maxRangeHostile;
+}
+
+int32 SpellInfo::GetDuration() const
+{
+ if (!DurationEntry)
+ return 0;
+ return (DurationEntry->Duration[0] == -1) ? -1 : abs(DurationEntry->Duration[0]);
+}
+
+int32 SpellInfo::GetMaxDuration() const
+{
+ if (!DurationEntry)
+ return 0;
+ return (DurationEntry->Duration[2] == -1) ? -1 : abs(DurationEntry->Duration[2]);
+}
+
+uint32 SpellInfo::CalcCastTime(Unit* caster, Spell* spell) const
+{
+ // not all spells have cast time index and this is all is pasiive abilities
+ if (!CastTimeEntry)
+ return 0;
+
+ int32 castTime = CastTimeEntry->CastTime;
+
+ if (caster)
+ caster->ModSpellCastTime(this, castTime, spell);
+
+ if (Attributes & SPELL_ATTR0_REQ_AMMO && (!IsAutoRepeatRangedSpell()))
+ castTime += 500;
+
+ return (castTime > 0) ? uint32(castTime) : 0;
+}
+
+uint32 SpellInfo::GetRecoveryTime() const
+{
+ return RecoveryTime > CategoryRecoveryTime ? RecoveryTime : CategoryRecoveryTime;
+}
+
+uint32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const
+{
+ // Spell drain all exist power on cast (Only paladin lay of Hands)
+ if (AttributesEx & SPELL_ATTR1_DRAIN_ALL_POWER)
+ {
+ // If power type - health drain all
+ if (PowerType == POWER_HEALTH)
+ return caster->GetHealth();
+ // Else drain all power
+ if (PowerType < MAX_POWERS)
+ return caster->GetPower(Powers(PowerType));
+ sLog->outError("SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", PowerType, Id);
+ return 0;
+ }
+
+ // Base powerCost
+ int32 powerCost = ManaCost;
+ // PCT cost from total amount
+ if (ManaCostPercentage)
+ {
+ switch (PowerType)
+ {
+ // health as power used
+ case POWER_HEALTH:
+ powerCost += int32(CalculatePctU(caster->GetCreateHealth(), ManaCostPercentage));
+ break;
+ case POWER_MANA:
+ powerCost += int32(CalculatePctU(caster->GetCreateMana(), ManaCostPercentage));
+ break;
+ case POWER_RAGE:
+ case POWER_FOCUS:
+ case POWER_ENERGY:
+ case POWER_HAPPINESS:
+ powerCost += int32(CalculatePctU(caster->GetMaxPower(Powers(PowerType)), ManaCostPercentage));
+ break;
+ case POWER_RUNE:
+ case POWER_RUNIC_POWER:
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "CalculateManaCost: Not implemented yet!");
+ break;
+ default:
+ sLog->outError("CalculateManaCost: Unknown power type '%d' in spell %d", PowerType, Id);
+ return 0;
+ }
+ }
+ SpellSchools school = GetFirstSchoolInMask(schoolMask);
+ // Flat mod from caster auras by spell school
+ powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
+ // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
+ if (AttributesEx4 & SPELL_ATTR4_SPELL_VS_EXTEND_COST)
+ powerCost += caster->GetAttackTime(OFF_ATTACK) / 100;
+ // Apply cost mod by spell
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(Id, SPELLMOD_COST, powerCost);
+
+ if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION)
+ powerCost = int32(powerCost / (1.117f * SpellLevel / caster->getLevel() -0.1327f));
+
+ // PCT mod from user auras by school
+ powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school)));
+ if (powerCost < 0)
+ powerCost = 0;
+ return powerCost;
+}
+
+bool SpellInfo::IsRanked() const
+{
+ return ChainEntry != NULL;
+}
+
+uint8 SpellInfo::GetRank() const
+{
+ if (!ChainEntry)
+ return 1;
+ return ChainEntry->rank;
+}
+
+SpellInfo const* SpellInfo::GetFirstRankSpell() const
+{
+ if (!ChainEntry)
+ return this;
+ return ChainEntry->first;
+}
+SpellInfo const* SpellInfo::GetLastRankSpell() const
+{
+ if (!ChainEntry)
+ return NULL;
+ return ChainEntry->last;
+}
+SpellInfo const* SpellInfo::GetNextRankSpell() const
+{
+ if (!ChainEntry)
+ return NULL;
+ return ChainEntry->next;
+}
+SpellInfo const* SpellInfo::GetPrevRankSpell() const
+{
+ if (!ChainEntry)
+ return NULL;
+ return ChainEntry->prev;
+}
+
+SpellInfo const* SpellInfo::GetAuraRankForLevel(uint8 level) const
+{
+ // ignore passive spells
+ if (IsPassive())
+ return this;
+
+ bool needRankSelection = false;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (IsPositiveEffect(i) &&
+ (Effects[i].Effect == SPELL_EFFECT_APPLY_AURA ||
+ Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_PARTY ||
+ Effects[i].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID))
+ {
+ needRankSelection = true;
+ break;
+ }
+ }
+
+ // not required
+ if (!needRankSelection)
+ return this;
+
+ for (SpellInfo const* nextSpellInfo = this; nextSpellInfo != NULL; nextSpellInfo = nextSpellInfo->GetPrevRankSpell())
+ {
+ // if found appropriate level
+ if (uint32(level + 10) >= nextSpellInfo->SpellLevel)
+ return nextSpellInfo;
+
+ // one rank less then
+ }
+
+ // not found
+ return NULL;
+}
+
+bool SpellInfo::IsRankOf(SpellInfo const* spellInfo) const
+{
+ return GetFirstRankSpell() == spellInfo->GetFirstRankSpell();
+}
+
+bool SpellInfo::IsDifferentRankOf(SpellInfo const* spellInfo) const
+{
+ if (Id == spellInfo->Id)
+ return false;
+ return IsRankOf(spellInfo);
+}
+
+bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const
+{
+ if (ChainEntry && spellInfo->ChainEntry)
+ {
+ if (ChainEntry->first == spellInfo->ChainEntry->first)
+ if (ChainEntry->rank > spellInfo->ChainEntry->rank)
+ return true;
+ }
+ return false;
+}
+
+bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
+{
+ // not found a single positive spell with this attribute
+ if (Attributes & SPELL_ATTR0_NEGATIVE_1)
+ return false;
+
+ switch (SpellFamilyName)
+ {
+ case SPELLFAMILY_GENERIC:
+ switch (Id)
+ {
+ case 34700: // Allergic Reaction
+ case 61716: // Rabbit Costume
+ case 61734: // Noblegarden Bunny
+ case 61987: // Avenging Wrath Marker
+ case 61988: // Divine Shield exclude aura
+ case 62532: // Conservator's Grip
+ return false;
+ case 30877: // Tag Murloc
+ case 62344: // Fists of Stone
+ return true;
+ default:
+ break;
+ }
+ break;
+ case SPELLFAMILY_MAGE:
+ // Amplify Magic, Dampen Magic
+ if (SpellFamilyFlags[0] == 0x00002000)
+ return true;
+ // Ignite
+ if (SpellIconID == 45)
+ return true;
+ break;
+ case SPELLFAMILY_PRIEST:
+ switch (Id)
+ {
+ case 64844: // Divine Hymn
+ case 64904: // Hymn of Hope
+ case 47585: // Dispersion
+ return true;
+ default:
+ break;
+ }
+ break;
+ case SPELLFAMILY_HUNTER:
+ // Aspect of the Viper
+ if (Id == 34074)
+ return true;
+ break;
+ case SPELLFAMILY_SHAMAN:
+ if (Id == 30708)
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ switch (Mechanic)
+ {
+ case MECHANIC_IMMUNE_SHIELD:
+ return true;
+ default:
+ break;
+ }
+
+ // Special case: effects which determine positivity of whole spell
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (Effects[i].ApplyAuraName == SPELL_AURA_MOD_STEALTH)
+ return true;
+ }
+
+ switch (Effects[effIndex].Effect)
+ {
+ case SPELL_EFFECT_DUMMY:
+ // some explicitly required dummy effect sets
+ switch (Id)
+ {
+ case 28441:
+ return false; // AB Effect 000
+ default:
+ break;
+ }
+ break;
+ // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
+ case SPELL_EFFECT_HEAL:
+ case SPELL_EFFECT_LEARN_SPELL:
+ case SPELL_EFFECT_SKILL_STEP:
+ case SPELL_EFFECT_HEAL_PCT:
+ case SPELL_EFFECT_ENERGIZE_PCT:
+ return true;
+
+ // non-positive aura use
+ case SPELL_EFFECT_APPLY_AURA:
+ case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
+ {
+ switch (Effects[effIndex].ApplyAuraName)
+ {
+ case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative)
+ case SPELL_AURA_MOD_STAT:
+ case SPELL_AURA_MOD_SKILL:
+ case SPELL_AURA_MOD_DODGE_PERCENT:
+ case SPELL_AURA_MOD_HEALING_PCT:
+ case SPELL_AURA_MOD_HEALING_DONE:
+ case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
+ if (Effects[effIndex].CalcValue() < 0)
+ return false;
+ break;
+ case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative)
+ if (Effects[effIndex].CalcValue() > 0)
+ return false;
+ break;
+ case SPELL_AURA_MOD_CRIT_PCT:
+ case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
+ if (Effects[effIndex].CalcValue() > 0)
+ return true; // some expected positive spells have SPELL_ATTR1_NEGATIVE
+ break;
+ case SPELL_AURA_ADD_TARGET_TRIGGER:
+ return true;
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ if (!deep)
+ {
+ if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell))
+ {
+ // negative targets of main spell return early
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (!spellTriggeredProto->Effects[i].Effect)
+ continue;
+ // if non-positive trigger cast targeted to positive target this main cast is non-positive
+ // this will place this spell auras as debuffs
+ if (_IsPositiveTarget(spellTriggeredProto->Effects[i].TargetA, spellTriggeredProto->Effects[effIndex].TargetB) && !spellTriggeredProto->_IsPositiveEffect(i, true))
+ return false;
+ }
+ }
+ }
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example)
+ break;
+ case SPELL_AURA_MOD_STUN: //have positive and negative spells, we can't sort its correctly at this moment.
+ if (effIndex == 0 && Effects[1].Effect == 0 && Effects[2].Effect == 0)
+ return false; // but all single stun aura spells is negative
+ break;
+ case SPELL_AURA_MOD_PACIFY_SILENCE:
+ if (Id == 24740) // Wisp Costume
+ return true;
+ return false;
+ case SPELL_AURA_MOD_ROOT:
+ case SPELL_AURA_MOD_SILENCE:
+ case SPELL_AURA_GHOST:
+ case SPELL_AURA_PERIODIC_LEECH:
+ case SPELL_AURA_MOD_STALKED:
+ case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
+ case SPELL_AURA_PREVENT_RESSURECTION:
+ return false;
+ case SPELL_AURA_PERIODIC_DAMAGE: // used in positive spells also.
+ // part of negative spell if casted at self (prevent cancel)
+ if (Effects[effIndex].TargetA == TARGET_UNIT_CASTER)
+ return false;
+ break;
+ case SPELL_AURA_MOD_DECREASE_SPEED: // used in positive spells also
+ // part of positive spell if casted at self
+ if (Effects[effIndex].TargetA != TARGET_UNIT_CASTER)
+ return false;
+ // but not this if this first effect (didn't find better check)
+ if (Attributes & SPELL_ATTR0_NEGATIVE_1 && effIndex == 0)
+ return false;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ {
+ // non-positive immunities
+ switch (Effects[effIndex].MiscValue)
+ {
+ case MECHANIC_BANDAGE:
+ case MECHANIC_SHIELD:
+ case MECHANIC_MOUNT:
+ case MECHANIC_INVULNERABILITY:
+ return false;
+ default:
+ break;
+ }
+ break;
+ }
+ case SPELL_AURA_ADD_FLAT_MODIFIER: // mods
+ case SPELL_AURA_ADD_PCT_MODIFIER:
+ {
+ // non-positive mods
+ switch (Effects[effIndex].MiscValue)
+ {
+ case SPELLMOD_COST: // dependent from bas point sign (negative -> positive)
+ if (Effects[effIndex].CalcValue() > 0)
+ {
+ if (!deep)
+ {
+ bool negative = true;
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ {
+ if (i != effIndex)
+ if (_IsPositiveEffect(i, true))
+ {
+ negative = false;
+ break;
+ }
+ }
+ if (negative)
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ // non-positive targets
+ if (!_IsPositiveTarget(Effects[effIndex].TargetA, Effects[effIndex].TargetB))
+ return false;
+
+ // negative spell if triggered spell is negative
+ if (!deep && !Effects[effIndex].ApplyAuraName && Effects[effIndex].TriggerSpell)
+ {
+ if (SpellInfo const* spellTriggeredProto = sSpellMgr->GetSpellInfo(Effects[effIndex].TriggerSpell))
+ if (!spellTriggeredProto->_IsPositiveSpell())
+ return false;
+ }
+
+ // ok, positive
+ return true;
+}
+
+bool SpellInfo::_IsPositiveSpell() const
+{
+ // spells with at least one negative effect are considered negative
+ // some self-applied spells have negative effects but in self casting case negative check ignored.
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (!_IsPositiveEffect(i, true))
+ return false;
+ return true;
+}
+
+bool SpellInfo::_IsPositiveTarget(uint32 targetA, uint32 targetB)
+{
+ // non-positive targets
+ switch (targetA)
+ {
+ case TARGET_UNIT_NEARBY_ENEMY:
+ case TARGET_UNIT_TARGET_ENEMY:
+ case TARGET_UNIT_AREA_ENEMY_SRC:
+ case TARGET_UNIT_AREA_ENEMY_DST:
+ case TARGET_UNIT_CONE_ENEMY:
+ case TARGET_UNIT_AREA_PATH:
+ case TARGET_DEST_DYNOBJ_ENEMY:
+ case TARGET_DST_TARGET_ENEMY:
+ return false;
+ default:
+ break;
+ }
+ if (targetB)
+ return _IsPositiveTarget(targetB, 0);
+ return true;
+} \ No newline at end of file
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
new file mode 100644
index 00000000000..178246495cd
--- /dev/null
+++ b/src/server/game/Spells/SpellInfo.h
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _SPELLINFO_H
+#define _SPELLINFO_H
+
+#include "SharedDefines.h"
+
+class Unit;
+class Spell;
+class SpellInfo;
+struct SpellChainNode;
+struct SpellTargetPosition;
+struct SpellDurationEntry;
+struct SpellRangeEntry;
+struct SpellRadiusEntry;
+struct SpellEntry;
+struct SpellCastTimesEntry;
+
+enum SpellEffectTargetTypes
+{
+ SPELL_REQUIRE_NONE,
+ SPELL_REQUIRE_UNIT,
+ SPELL_REQUIRE_DEST,
+ SPELL_REQUIRE_ITEM,
+ SPELL_REQUIRE_CASTER,
+ SPELL_REQUIRE_GOBJECT,
+};
+
+enum SpellSelectTargetTypes
+{
+ TARGET_TYPE_DEFAULT,
+ TARGET_TYPE_UNIT_CASTER,
+ TARGET_TYPE_UNIT_TARGET,
+ TARGET_TYPE_UNIT_NEARBY,
+ TARGET_TYPE_AREA_SRC,
+ TARGET_TYPE_AREA_DST,
+ TARGET_TYPE_AREA_CONE,
+ TARGET_TYPE_DEST_CASTER,
+ TARGET_TYPE_DEST_TARGET,
+ TARGET_TYPE_DEST_DEST,
+ TARGET_TYPE_DEST_SPECIAL,
+ TARGET_TYPE_CHANNEL,
+};
+
+// Spell clasification
+enum SpellSpecificType
+{
+ SPELL_SPECIFIC_NORMAL = 0,
+ SPELL_SPECIFIC_SEAL = 1,
+ SPELL_SPECIFIC_AURA = 3,
+ SPELL_SPECIFIC_STING = 4,
+ SPELL_SPECIFIC_CURSE = 5,
+ SPELL_SPECIFIC_ASPECT = 6,
+ SPELL_SPECIFIC_TRACKER = 7,
+ SPELL_SPECIFIC_WARLOCK_ARMOR = 8,
+ SPELL_SPECIFIC_MAGE_ARMOR = 9,
+ SPELL_SPECIFIC_ELEMENTAL_SHIELD = 10,
+ SPELL_SPECIFIC_MAGE_POLYMORPH = 11,
+ SPELL_SPECIFIC_JUDGEMENT = 13,
+ SPELL_SPECIFIC_WARLOCK_CORRUPTION= 17,
+ SPELL_SPECIFIC_FOOD = 19,
+ SPELL_SPECIFIC_DRINK = 20,
+ SPELL_SPECIFIC_FOOD_AND_DRINK = 21,
+ SPELL_SPECIFIC_PRESENCE = 22,
+ SPELL_SPECIFIC_CHARM = 23,
+ SPELL_SPECIFIC_SCROLL = 24,
+ SPELL_SPECIFIC_MAGE_ARCANE_BRILLANCE = 25,
+ SPELL_SPECIFIC_WARRIOR_ENRAGE = 26,
+ SPELL_SPECIFIC_PRIEST_DIVINE_SPIRIT = 27,
+ SPELL_SPECIFIC_HAND = 28,
+ SPELL_SPECIFIC_PHASE = 29,
+};
+
+enum SpellCustomAttributes
+{
+ SPELL_ATTR0_CU_ENCHANT_PROC = 0x00000001,
+ SPELL_ATTR0_CU_CONE_BACK = 0x00000002,
+ SPELL_ATTR0_CU_CONE_LINE = 0x00000004,
+ SPELL_ATTR0_CU_SHARE_DAMAGE = 0x00000008,
+ SPELL_ATTR0_CU_NONE1 = 0x00000010, // UNUSED
+ SPELL_ATTR0_CU_NONE2 = 0x00000020, // UNUSED
+ SPELL_ATTR0_CU_AURA_CC = 0x00000040,
+ SPELL_ATTR0_CU_DIRECT_DAMAGE = 0x00000100,
+ SPELL_ATTR0_CU_CHARGE = 0x00000200,
+ SPELL_ATTR0_CU_PICKPOCKET = 0x00000400,
+ SPELL_ATTR0_CU_EXCLUDE_SELF = 0x00000800,
+ SPELL_ATTR0_CU_NEGATIVE_EFF0 = 0x00001000,
+ SPELL_ATTR0_CU_NEGATIVE_EFF1 = 0x00002000,
+ SPELL_ATTR0_CU_NEGATIVE_EFF2 = 0x00004000,
+ SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000,
+ SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
+ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
+
+ SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2,
+};
+
+class SpellImplicitTargetInfo
+{
+private:
+ Targets _target;
+public:
+ SpellImplicitTargetInfo() {}
+ SpellImplicitTargetInfo(uint32 target);
+
+ bool IsArea() const;
+ SpellSelectTargetTypes GetType() const;
+
+ operator Targets() const;
+
+ // temporarily avalible to public
+ static bool IsPosition(uint32 targetType);
+ static SpellSelectTargetTypes Type[TOTAL_SPELL_TARGETS];
+
+private:
+ static bool InitStaticData();
+ static void InitAreaData();
+ static void InitTypeData();
+
+ static bool Init;
+ static bool Area[TOTAL_SPELL_TARGETS];
+};
+
+class SpellEffectInfo
+{
+ SpellInfo const* _spellInfo;
+ uint8 _effIndex;
+public:
+ uint32 Effect;
+ uint32 ApplyAuraName;
+ uint32 Amplitude;
+ int32 DieSides;
+ float RealPointsPerLevel;
+ int32 BasePoints;
+ float PointsPerComboPoint;
+ float ValueMultiplier;
+ float DamageMultiplier;
+ float BonusMultiplier;
+ int32 MiscValue;
+ int32 MiscValueB;
+ Mechanics Mechanic;
+ SpellImplicitTargetInfo TargetA;
+ SpellImplicitTargetInfo TargetB;
+ SpellRadiusEntry const* RadiusEntry;
+ uint32 ChainTarget;
+ uint32 ItemType;
+ uint32 TriggerSpell;
+ flag96 SpellClassMask;
+
+ SpellEffectInfo() {}
+ SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex);
+
+ bool IsEffect() const;
+ bool IsEffect(SpellEffects effectName) const;
+ bool IsAura() const;
+ bool IsAura(AuraType aura) const;
+ bool IsArea() const;
+ bool IsAreaAuraEffect() const;
+ bool IsFarUnitTargetEffect() const;
+ bool IsFarDestTargetEffect() const;
+ bool IsUnitOwnedAuraEffect() const;
+
+ int32 CalcValue(Unit const* caster = NULL, int32 const* basePoints = NULL, Unit const* target = NULL) const;
+ int32 CalcBaseValue(int32 value) const;
+ float CalcValueMultiplier(Unit* caster, Spell* spell = NULL) const;
+ float CalcDamageMultiplier(Unit* caster, Spell* spell = NULL) const;
+
+ bool HasRadius() const;
+ float CalcRadius(Unit* caster = NULL, Spell* = NULL) const;
+
+ SpellEffectTargetTypes GetRequiredTargetType() const;
+
+private:
+ static bool InitStaticData();
+ static void InitRequiredTargetTypeData();
+
+ static bool Init;
+ static SpellEffectTargetTypes RequiredTargetType[TOTAL_SPELL_EFFECTS];
+};
+
+class SpellInfo
+{
+public:
+ uint32 Id;
+ uint32 Category;
+ uint32 Dispel;
+ uint32 Mechanic;
+ uint32 Attributes;
+ uint32 AttributesEx;
+ uint32 AttributesEx2;
+ uint32 AttributesEx3;
+ uint32 AttributesEx4;
+ uint32 AttributesEx5;
+ uint32 AttributesEx6;
+ uint32 AttributesEx7;
+ uint32 AttributesCu;
+ uint32 Stances;
+ uint32 StancesNot;
+ uint32 Targets;
+ uint32 TargetCreatureType;
+ uint32 RequiresSpellFocus;
+ uint32 FacingCasterFlags;
+ uint32 CasterAuraState;
+ uint32 TargetAuraState;
+ uint32 CasterAuraStateNot;
+ uint32 TargetAuraStateNot;
+ uint32 CasterAuraSpell;
+ uint32 TargetAuraSpell;
+ uint32 ExcludeCasterAuraSpell;
+ uint32 ExcludeTargetAuraSpell;
+ SpellCastTimesEntry const* CastTimeEntry;
+ uint32 RecoveryTime;
+ uint32 CategoryRecoveryTime;
+ uint32 StartRecoveryCategory;
+ uint32 StartRecoveryTime;
+ uint32 InterruptFlags;
+ uint32 AuraInterruptFlags;
+ uint32 ChannelInterruptFlags;
+ uint32 ProcFlags;
+ uint32 ProcChance;
+ uint32 ProcCharges;
+ uint32 MaxLevel;
+ uint32 BaseLevel;
+ uint32 SpellLevel;
+ SpellDurationEntry const* DurationEntry;
+ uint32 PowerType;
+ uint32 ManaCost;
+ uint32 ManaCostPerlevel;
+ uint32 ManaPerSecond;
+ uint32 ManaPerSecondPerLevel;
+ uint32 ManaCostPercentage;
+ uint32 RuneCostID;
+ SpellRangeEntry const* RangeEntry;
+ float Speed;
+ uint32 StackAmount;
+ uint32 Totem[2];
+ int32 Reagent[MAX_SPELL_REAGENTS];
+ uint32 ReagentCount[MAX_SPELL_REAGENTS];
+ int32 EquippedItemClass;
+ int32 EquippedItemSubClassMask;
+ int32 EquippedItemInventoryTypeMask;
+ uint32 TotemCategory[2];
+ uint32 SpellVisual[2];
+ uint32 SpellIconID;
+ uint32 ActiveIconID;
+ char* SpellName[16];
+ char* Rank[16];
+ uint32 MaxTargetLevel;
+ uint32 MaxAffectedTargets;
+ uint32 SpellFamilyName;
+ flag96 SpellFamilyFlags;
+ uint32 DmgClass;
+ uint32 PreventionType;
+ int32 AreaGroupId;
+ uint32 SchoolMask;
+ SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
+ SpellChainNode const* ChainEntry;
+
+ SpellInfo(SpellEntry const* spellEntry);
+
+ bool HasEffect(SpellEffects effect) const;
+ bool HasAura(AuraType aura) const;
+ bool HasAreaAuraEffect() const;
+
+ bool IsExplicitDiscovery() const;
+ bool IsLootCrafting() const;
+ bool IsQuestTame() const;
+ bool IsProfessionOrRiding() const;
+ bool IsProfession() const;
+ bool IsPrimaryProfession() const;
+ bool IsPrimaryProfessionFirstRank() const;
+ bool IsAbilityLearnedWithProfession() const;
+ bool IsAbilityOfSkillType(uint32 skillType) const;
+
+ bool IsAOE() const;
+ bool IsRequiringSelectedTarget() const;
+
+ bool IsPassive() const;
+ bool IsAutocastable() const;
+ bool IsStackableWithRanks() const;
+ bool IsPassiveStackableWithRanks() const;
+ bool IsMultiSlotAura() const;
+ bool IsDeathPersistent() const;
+ bool IsRequiringDeadTarget() const;
+ bool IsAllowingDeadTarget() const;
+ bool CanBeUsedInCombat() const;
+ bool IsPositive() const;
+ bool IsPositiveEffect(uint8 effIndex) const;
+ bool IsChanneled() const;
+ bool NeedsComboPoints() const;
+ bool IsBreakingStealth() const;
+ bool IsRangedWeaponSpell() const;
+ bool IsAutoRepeatRangedSpell() const;
+
+ bool IsAffectedBySpellMod(SpellModifier* mod) const;
+
+ bool CanPierceImmuneAura(SpellInfo const* aura) const;
+ bool CanDispelAura(SpellInfo const* aura) const;
+
+ bool IsSingleTarget() const;
+ bool IsSingleTargetWith(SpellInfo const* spellInfo) const;
+ bool IsAuraExclusiveBySpecificWith(SpellInfo const* spellInfo) const;
+ bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
+
+ SpellCastResult CheckShapeshift(uint32 form) const;
+ SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const;
+
+ SpellSchoolMask GetSchoolMask() const;
+ uint32 GetAllEffectsMechanicMask() const;
+ uint32 GetEffectMechanicMask(uint8 effIndex) const;
+ Mechanics GetEffectMechanic(uint8 effIndex) const;
+ uint32 GetDispelMask() const;
+ static uint32 GetDispelMask(DispelType type);
+
+ AuraStateType GetAuraState() const;
+ SpellSpecificType GetSpellSpecific() const;
+
+ float GetMinRange(bool positive = false) const;
+ float GetMaxRange(bool positive = false) const;
+
+ int32 GetDuration() const;
+ int32 GetMaxDuration() const;
+
+ uint32 CalcCastTime(Unit* caster = NULL, Spell* spell = NULL) const;
+ uint32 GetRecoveryTime() const;
+
+ uint32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const;
+
+ bool IsRanked() const;
+ uint8 GetRank() const;
+ SpellInfo const* GetFirstRankSpell() const;
+ SpellInfo const* GetLastRankSpell() const;
+ SpellInfo const* GetNextRankSpell() const;
+ SpellInfo const* GetPrevRankSpell() const;
+ SpellInfo const* GetAuraRankForLevel(uint8 level) const;
+ bool IsRankOf(SpellInfo const* spellInfo) const;
+ bool IsDifferentRankOf(SpellInfo const* spellInfo) const;
+ bool IsHighRankOf(SpellInfo const* spellInfo) const;
+
+ // loading helpers
+ bool _IsPositiveEffect(uint8 effIndex, bool deep) const;
+ bool _IsPositiveSpell() const;
+ static bool _IsPositiveTarget(uint32 targetA, uint32 targetB);
+};
+
+#endif // _SPELLINFO_H \ No newline at end of file