diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 1942 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 360 |
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 |