server/src/game/WorldHandlers/SpellEffects.cpp
Charles A Edwards df3ab5df8e 13 cmangos commits implemented
commits:

432bd63 Commit Ported  Core Implement TakePossessOf to generalize the
code.
0b663eb Commit Ported  Core Implement a possibility to summon manualy a

temporary creature.
b6a9ead Commit Imported  Core Little rewrite of resurect code to prepare
ability
ro resurrect a player to a ghoul form.
e98b42c Commit Imported  Core Implement TemporarySummon Linked aura to
owner.
ab139ff Commit Imported  Core Do not force the creature to attack
summoner in all
case
555f055 Commit Imported  Core Avoid possibility to charm more than one
new
creature for an unit.
fd78c4a Commit Imported  Core Fix problem that occur when the charm unit
field is
updated after the possess bar.
e9821e2 Commit Imported  Core fix lightwell gameobject not appearing
after spell
is cast
17d0e93 Commit Imported  Core Implement logic for Target 95 as
TARGET_VEHICLE_DRIVER
42b3545 Commit Imported  Core Now npc/gameobject interaction will remove

unauthorized aura
1195398 Commit Imported  Core Improve functionality for eventAI action
26 -
ACTION_T_QUEST_EVENT_ALL
72b7a48 Commit Ported  Core fix pet stay
245f068 Commit Imported  Warlock [Charm] prevent charming multiple
demons also remove
pet temporarily when casting specific channels that summon other charmed
creatures
2020-02-17 12:10:28 +00:00

11940 lines
505 KiB
C++

/**
* MaNGOS is a full featured server for World of Warcraft, supporting
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
*
* Copyright (C) 2005-2016 MaNGOS project <https://getmangos.eu>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
* and lore are copyrighted by Blizzard Entertainment, Inc.
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
#include "UpdateMask.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "SkillExtraItems.h"
#include "Unit.h"
#include "Spell.h"
#include "DynamicObject.h"
#include "SpellAuras.h"
#include "Group.h"
#include "UpdateData.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "SharedDefines.h"
#include "Pet.h"
#include "GameObject.h"
#include "GossipDef.h"
#include "Creature.h"
#include "Totem.h"
#include "CreatureAI.h"
#include "BattleGround/BattleGroundMgr.h"
#include "BattleGround/BattleGround.h"
#include "BattleGround/BattleGroundEY.h"
#include "BattleGround/BattleGroundWS.h"
#include "Language.h"
#include "SocialMgr.h"
#include "VMapFactory.h"
#include "Util.h"
#include "TemporarySummon.h"
#include "ScriptMgr.h"
#include "SkillDiscovery.h"
#include "Formulas.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "Vehicle.h"
#include "G3D/Vector3.h"
#include "LootMgr.h"
pEffect SpellEffects[TOTAL_SPELL_EFFECTS] =
{
&Spell::EffectNULL, // 0
&Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
&Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
&Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
&Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused from pre-1.2.1
&Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
&Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
&Spell::EffectEnvironmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
&Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
&Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
&Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
&Spell::EffectBind, // 11 SPELL_EFFECT_BIND
&Spell::EffectUnused, // 12 SPELL_EFFECT_PORTAL unused from pre-1.2.1, exist 2 spell, but not exist any data about its real usage
&Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused from pre-1.2.1
&Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused from pre-1.2.1
&Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused from pre-1.2.1
&Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
&Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
&Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
&Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
&Spell::EffectEmpty, // 20 SPELL_EFFECT_DODGE one spell: Dodge
&Spell::EffectEmpty, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
&Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
&Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
&Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
&Spell::EffectEmpty, // 25 SPELL_EFFECT_WEAPON spell per weapon type, in ItemSubclassmask store mask that can be used for usability check at equip, but current way using skill also work.
&Spell::EffectEmpty, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
&Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
&Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
&Spell::EffectLeapForward, // 29 SPELL_EFFECT_LEAP
&Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
&Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
&Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
&Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
&Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
&Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
&Spell::EffectEmpty, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
&Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
&Spell::EffectEmpty, // 39 SPELL_EFFECT_LANGUAGE misc store lang id
&Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
&Spell::EffectJump, // 41 SPELL_EFFECT_JUMP
&Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
&Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
&Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
&Spell::EffectNULL, // 45 SPELL_EFFECT_PLAY_MOVIE
&Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN spawn/login animation, expected by spawn unit cast, also base points store some dynflags
&Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
&Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
&Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
&Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
&Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused from pre-1.2.1
&Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT unused from pre-1.2.1
&Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
&Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
&Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
&Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
&Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
&Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
&Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot
&Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
&Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
&Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
&Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
&Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
&Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
&Spell::EffectRestoreItemCharges, // 66 SPELL_EFFECT_RESTORE_ITEM_CHARGES itemtype - is affected item ID
&Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
&Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
&Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
&Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
&Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
&Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
&Spell::EffectNULL, // 73 SPELL_EFFECT_UNTRAIN_TALENTS one spell: Trainer: Untrain Talents
&Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
&Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
&Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
&Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
&Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
&Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
&Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
&Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
&Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
&Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
&Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
&Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
&Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
&Spell::EffectWMODamage, // 87 SPELL_EFFECT_WMO_DAMAGE (57 spells in 3.3.2)
&Spell::EffectWMORepair, // 88 SPELL_EFFECT_WMO_REPAIR (2 spells in 3.3.2)
&Spell::EffectWMOChange, // 89 SPELL_EFFECT_WMO_CHANGE (7 spells in 3.3.2)
&Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT_PERSONAL Kill credit but only for single person
&Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
&Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
&Spell::EffectBreakPlayerTargeting, // 93 SPELL_EFFECT_BREAK_PLAYER_TARGETING
&Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
&Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
&Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
&Spell::EffectSummonAllTotems, // 97 SPELL_EFFECT_SUMMON_ALL_TOTEMS
&Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
&Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
&Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
&Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
&Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
&Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
&Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT
&Spell::EffectNULL, //105 SPELL_EFFECT_SURVEY
&Spell::EffectNULL, //106 SPELL_EFFECT_SUMMON_RAID_MARKER
&Spell::EffectNULL, //107 SPELL_EFFECT_LOOT_CORPSE
&Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
&Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
&Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
&Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
&Spell::EffectUnused, //112 SPELL_EFFECT_112 (old SPELL_EFFECT_SUMMON_DEMON)
&Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
&Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
&Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
&Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
&Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
&Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
&Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
&Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
&Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
&Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
&Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
&Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
&Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
&Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
&Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
&Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
&Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
&Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
&Spell::EffectPlaySound, //131 SPELL_EFFECT_PLAY_SOUND sound id in misc value (SoundEntries.dbc)
&Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
&Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
&Spell::EffectKillCreditGroup, //134 SPELL_EFFECT_KILL_CREDIT_GROUP misc value is creature entry
&Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
&Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
&Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
&Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back
&Spell::EffectClearQuest, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
&Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
&Spell::EffectForceCast, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE
&Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
&Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
&Spell::EffectKnockBackFromPosition, //144 SPELL_EFFECT_KNOCKBACK_FROM_POSITION
&Spell::EffectGravityPull, //145 SPELL_EFFECT_GRAVITY_PULL
&Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
&Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
&Spell::EffectNULL, //148 SPELL_EFFECT_148 single spell: Inflicts Fire damage to an enemy.
&Spell::EffectCharge2, //149 SPELL_EFFECT_CHARGE2 swoop
&Spell::EffectQuestOffer, //150 SPELL_EFFECT_QUEST_OFFER
&Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
&Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
&Spell::EffectCreateTamedPet, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
&Spell::EffectTeachTaxiNode, //154 SPELL_EFFECT_TEACH_TAXI_NODE single spell: Teach River's Heart Taxi Path
&Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
&Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
&Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item
&Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
&Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
&Spell::EffectNULL, //160 SPELL_EFFECT_160 single spell: Nerub'ar Web Random Unit
&Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert)
&Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec
&Spell::EffectUnused, //163 unused in 3.3.5a
&Spell::EffectCancelAura, //164 SPELL_EFFECT_CANCEL_AURA
&Spell::EffectNULL, //165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT 82 spells in 4.3.4
&Spell::EffectNULL, //166 SPELL_EFFECT_REWARD_CURRENCY 56 spells in 4.3.4
&Spell::EffectNULL, //167 SPELL_EFFECT_167 42 spells in 4.3.4
&Spell::EffectNULL, //168 SPELL_EFFECT_168 2 spells in 4.3.4 Allows give commands to controlled pet
&Spell::EffectNULL, //169 SPELL_EFFECT_DESTROY_ITEM 9 spells in 4.3.4
&Spell::EffectNULL, //170 SPELL_EFFECT_170 70 spells in 4.3.4
&Spell::EffectNULL, //171 SPELL_EFFECT_171 19 spells in 4.3.4 related to GO summon
&Spell::EffectNULL, //172 SPELL_EFFECT_MASS_RESSURECTION Mass Ressurection (Guild Perk)
&Spell::EffectNULL, //173 SPELL_EFFECT_BUY_GUILD_BANKSLOT 4 spells in 4.3.4 basepoints - slot
&Spell::EffectNULL, //174 SPELL_EFFECT_174 13 spells some sort of area aura apply effect
&Spell::EffectUnused, //175 SPELL_EFFECT_175 unused in 4.3.4
&Spell::EffectNULL, //176 SPELL_EFFECT_SANCTUARY_2 4 spells in 4.3.4
&Spell::EffectNULL, //177 SPELL_EFFECT_177 2 spells in 4.3.4 Deluge(100757) and test spell
&Spell::EffectUnused, //178 SPELL_EFFECT_178 unused in 4.3.4
&Spell::EffectNULL, //179 SPELL_EFFECT_179 15 spells in 4.3.4
&Spell::EffectUnused, //180 SPELL_EFFECT_180 unused in 4.3.4
&Spell::EffectUnused, //181 SPELL_EFFECT_181 unused in 4.3.4
&Spell::EffectNULL, //182 SPELL_EFFECT_182 3 spells 4.3.4
};
void Spell::EffectEmpty(SpellEffectEntry const* /*effect*/)
{
// NOT NEED ANY IMPLEMENTATION CODE, EFFECT POSISBLE USED AS MARKER OR CLIENT INFORM
}
void Spell::EffectNULL(SpellEffectEntry const* /*effect*/)
{
DEBUG_LOG("WORLD: Spell Effect DUMMY");
}
void Spell::EffectUnused(SpellEffectEntry const* /*effect*/)
{
// NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
}
void Spell::EffectResurrectNew(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->IsAlive())
return;
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!unitTarget->IsInWorld())
return;
Player* pTarget = ((Player*)unitTarget);
if (pTarget->isRessurectRequested()) // already have one active request
return;
uint32 health = damage;
uint32 mana = effect->EffectMiscValue;
pTarget->setResurrectRequestData(m_caster->GetObjectGuid(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
SendResurrectRequest(pTarget);
}
void Spell::EffectInstaKill(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || !unitTarget->IsAlive())
return;
if (m_caster == unitTarget) // prevent interrupt message
finish();
WorldObject* caster = GetCastingObject(); // we need the original casting object
WorldPacket data(SMSG_SPELLINSTAKILLLOG, (8 + 8 + 4));
data << (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT ? m_caster->GetObjectGuid() : ObjectGuid()); // Caster GUID
data << unitTarget->GetObjectGuid(); // Victim GUID
data << uint32(m_spellInfo->Id);
m_caster->SendMessageToSet(&data, true);
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, m_spellInfo, false);
}
void Spell::EffectEnvironmentalDMG(SpellEffectEntry const* effect)
{
uint32 absorb = 0;
uint32 resist = 0;
// Note: this hack with damage replace required until GO casting not implemented
// environment damage spells already have around enemies targeting but this not help in case nonexistent GO casting support
// currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
damage = effect->CalculateSimpleValue();
m_caster->CalculateDamageAbsorbAndResist(m_caster, GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
((Player*)m_caster)->EnvironmentalDamage(DAMAGE_FIRE, damage);
}
void Spell::EffectSchoolDMG(SpellEffectEntry const* effect)
{
if (unitTarget && unitTarget->IsAlive())
{
SpellClassOptionsEntry const* classOptions = m_spellInfo->GetSpellClassOptions();
switch(m_spellInfo->GetSpellFamilyName())
{
case SPELLFAMILY_GENERIC:
{
switch (m_spellInfo->Id) // better way to check unknown
{
// Meteor like spells (divided damage to targets)
case 24340: case 26558: case 28884: // Meteor
case 36837: case 38903: case 41276: // Meteor
case 57467: // Meteor
case 26789: // Shard of the Fallen Star
case 31436: // Malevolent Cleave
case 35181: // Dive Bomb
case 40810: case 43267: case 43268: // Saber Lash
case 42384: // Brutal Swipe
case 45150: // Meteor Slash
case 64422: case 64688: // Sonic Screech
case 70492: case 72505: // Ooze Eruption
case 71904: // Chaos Bane
case 72624: case 72625: // Ooze Eruption
case 77679: case 92968: case 92969: case 92970: // Scorching Blast
case 82935: case 88915: case 88916: case 88917: // Caustic Slime
case 86014: case 92863: case 92864: case 92865: // Twilight Meteorite
case 86367: case 93135: case 93136: case 93137: // Sleet Storm
case 86825: case 92879: case 92880: case 92881: // Blackout
case 88942: case 95172: // Meteor Slash
case 89348: case 95178: // Demon Repellent Ray
case 98474: case 100212: case 100213: case 100214: //Flame Scythe
case 103414: case 108571: case 109033: case 109034: //Stomp
case 105069: case 108094: // Seething Hate
case 106375: case 109182: case 109183: case 109184: //Twilight Unstable
{
uint32 count = 0;
for(TargetList::const_iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
if(ihit->effectMask & (1<<effect->EffectIndex))
++count;
damage /= count; // divide to all targets
break;
}
// percent from health with min
case 25599: // Thundercrash
{
damage = unitTarget->GetHealth() / 2;
if (damage < 200)
damage = 200;
break;
}
// Intercept (warrior spell trigger)
case 20253:
case 61491:
{
damage += uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
break;
}
// percent max target health
case 29142: // Eyesore Blaster
case 35139: // Throw Boom's Doom
case 49882: // Leviroth Self-Impale
case 55269: // Deathly Stare
{
damage = damage * unitTarget->GetMaxHealth() / 100;
break;
}
// Cataclysmic Bolt
case 38441:
{
damage = unitTarget->GetMaxHealth() / 2;
break;
}
// Touch the Nightmare
case 50341:
{
if (SpellEffectIndex(effect->EffectIndex) == EFFECT_INDEX_2)
damage = int32(unitTarget->GetMaxHealth() * 0.3f);
break;
}
// Tympanic Tantrum
case 62775:
{
damage = unitTarget->GetMaxHealth() / 10;
break;
}
// Hand of Rekoning (name not have typos ;) )
case 67485:
damage += uint32(0.5f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
break;
// Magic Bane normal (Forge of Souls - Bronjahm)
case 68793:
{
damage += uint32(unitTarget->GetMaxPower(POWER_MANA) / 2);
damage = std::min(damage, 10000);
break;
}
// Magic Bane heroic (Forge of Souls - Bronjahm)
case 69050:
{
damage += uint32(unitTarget->GetMaxPower(POWER_MANA) / 2);
damage = std::min(damage, 15000);
break;
}
}
break;
}
case SPELLFAMILY_MAGE:
// remove Arcane Blast buffs at any non-Arcane Blast arcane damage spell.
// NOTE: it removed at hit instead cast because currently spell done-damage calculated at hit instead cast
if ((m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_ARCANE) && !(classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x20000000)))
m_caster->RemoveAurasDueToSpell(36032); // Arcane Blast buff
break;
case SPELLFAMILY_WARRIOR:
{
// Bloodthirst
if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x40000000000))
{
damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
}
// Victory Rush
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x10000000000))
{
damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
}
// Revenge ${$m1+$AP*0.310} to ${$M1+$AP*0.310}
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000400))
damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.310f);
// Heroic Throw ${$m1+$AP*.50}
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000100000000))
damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
// Shattering Throw ${$m1+$AP*.50}
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0040000000000000))
damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
// Shockwave ${$m3/100*$AP}
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000800000000000))
{
int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_INDEX_2);
if (pct > 0)
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
break;
}
// Thunder Clap
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000080))
{
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 12 / 100);
}
break;
}
case SPELLFAMILY_WARLOCK:
{
// Incinerate Rank 1 & 2
if ((classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00004000000000)) && m_spellInfo->SpellIconID==2128)
{
// Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff.
// Check aura state for speed but aura state set not only for Immolate spell
if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE))
{
Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for (Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{
// Immolate
SpellClassOptionsEntry const* immSpellClassOpt = (*i)->GetSpellProto()->GetSpellClassOptions();
if(!immSpellClassOpt)
continue;
if(immSpellClassOpt->SpellFamilyName == SPELLFAMILY_WARLOCK &&
(immSpellClassOpt->SpellFamilyFlags & UI64LIT(0x00000000000004)))
{
damage += damage / 4;
break;
}
}
}
}
// Shadowflame
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0001000000000000))
{
// Apply DOT part
switch (m_spellInfo->Id)
{
case 47897: m_caster->CastSpell(unitTarget, 47960, true); break;
case 61290: m_caster->CastSpell(unitTarget, 61291, true); break;
default:
sLog.outError("Spell::EffectDummy: Unhandeled Shadowflame spell rank %u", m_spellInfo->Id);
break;
}
}
// Shadow Bite
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0040000000000000))
{
Unit* owner = m_caster->GetOwner();
if (!owner)
break;
uint32 counter = 0;
Unit::AuraList const& dotAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for (Unit::AuraList::const_iterator itr = dotAuras.begin(); itr != dotAuras.end(); ++itr)
if ((*itr)->GetCasterGuid() == owner->GetObjectGuid())
++counter;
if (counter)
damage += (counter * owner->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_INDEX_2) * damage) / 100.0f;
}
// Conflagrate - consumes Immolate or Shadowflame
else if (m_spellInfo->GetTargetAuraState() == AURA_STATE_CONFLAGRATE)
{
Aura const* aura = nullptr; // found req. aura for damage calculation
Unit::AuraList const& mPeriodic = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for (Unit::AuraList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
{
// for caster applied auras only
if ((*i)->GetSpellProto()->GetSpellFamilyName() != SPELLFAMILY_WARLOCK ||
(*i)->GetCasterGuid() != m_caster->GetObjectGuid())
continue;
// Immolate
if ((*i)->GetSpellProto()->IsFitToFamilyMask(UI64LIT(0x0000000000000004)))
{
aura = *i; // it selected always if exist
break;
}
// Shadowflame
if ((*i)->GetSpellProto()->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00000002))
aura = *i; // remember but wait possible Immolate as primary priority
}
// found Immolate or Shadowflame
if (aura)
{
int32 damagetick = aura->GetModifier()->m_amount;
damage += damagetick * 4;
// Glyph of Conflagrate
if (!m_caster->HasAura(56235))
unitTarget->RemoveAurasByCasterSpell(aura->GetId(), m_caster->GetObjectGuid());
break;
}
}
break;
}
case SPELLFAMILY_PRIEST:
{
// Shadow Word: Death - deals damage equal to damage done to caster
if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000200000000))
m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
// Improved Mind Blast (Mind Blast in shadow form bonus)
else if (m_caster->GetShapeshiftForm() == FORM_SHADOW && (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00002000)))
{
Unit::AuraList const& ImprMindBlast = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
for (Unit::AuraList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i)
{
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_PRIEST &&
((*i)->GetSpellProto()->SpellIconID == 95))
{
int chance = (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_1);
if (roll_chance_i(chance))
// Mind Trauma
m_caster->CastSpell(unitTarget, 48301, true);
break;
}
}
}
break;
}
case SPELLFAMILY_DRUID:
{
SpellEffectEntry const* rakeSpellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_2);
// Ferocious Bite
if (m_caster->GetTypeId()==TYPEID_PLAYER && (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x000800000)) && m_spellInfo->SpellVisual[0]==6587)
{
// converts up to 30 points of energy into ($f1+$AP/410) additional damage
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
float multiple = ap / 410 + effect->EffectDamageMultiplier;
damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
uint32 energy = m_caster->GetPower(POWER_ENERGY);
uint32 used_energy = energy > 30 ? 30 : energy;
damage += int32(used_energy * multiple);
m_caster->SetPower(POWER_ENERGY, energy - used_energy);
}
// Rake
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000001000) && rakeSpellEffect && rakeSpellEffect->Effect == SPELL_EFFECT_ADD_COMBO_POINTS)
{
// $AP*0.01 bonus
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
}
// Swipe
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0010000000000000))
{
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.08f);
}
break;
}
case SPELLFAMILY_ROGUE:
{
// Envenom
if (m_caster->GetTypeId()==TYPEID_PLAYER && (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x800000000)))
{
// consume from stack dozes not more that have combo-points
if (uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
Aura* poison = 0;
// Lookup for Deadly poison (only attacker applied)
Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
{
SpellClassOptionsEntry const* poisonClassOptions = (*itr)->GetSpellProto()->GetSpellClassOptions();
if(!poisonClassOptions)
continue;
if( poisonClassOptions->SpellFamilyName==SPELLFAMILY_ROGUE &&
(poisonClassOptions->SpellFamilyFlags & UI64LIT(0x10000)) &&
(*itr)->GetCasterGuid() == m_caster->GetObjectGuid())
{
poison = *itr;
break;
}
}
// count consumed deadly poison doses at target
if (poison)
{
bool needConsume = true;
uint32 spellId = poison->GetId();
uint32 doses = poison->GetStackAmount();
if (doses > combo)
doses = combo;
// Master Poisoner
Unit::AuraList const& auraList = ((Player*)m_caster)->GetAurasByType(SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL);
for (Unit::AuraList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
{
if ((*iter)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_ROGUE && (*iter)->GetSpellProto()->SpellIconID == 1960)
{
if (int32 chance = (*iter)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2))
if (roll_chance_i(chance))
needConsume = false;
break;
}
}
if (needConsume)
unitTarget->RemoveAuraHolderFromStack(spellId, doses, m_caster->GetObjectGuid());
damage *= doses;
damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * doses);
}
// Eviscerate and Envenom Bonus Damage (item set effect)
if (m_caster->GetDummyAura(37169))
damage += ((Player*)m_caster)->GetComboPoints() * 40;
}
}
// Eviscerate
else if ((classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00020000)) && m_caster->GetTypeId()==TYPEID_PLAYER)
{
if (uint32 combo = ((Player*)m_caster)->GetComboPoints())
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
// Eviscerate and Envenom Bonus Damage (item set effect)
if (m_caster->GetDummyAura(37169))
damage += combo * 40;
}
}
break;
}
case SPELLFAMILY_HUNTER:
{
// Gore
if (m_spellInfo->SpellIconID == 1578)
{
if (m_caster->HasAura(57627)) // Charge 6 sec post-affect
damage *= 2;
}
// Steady Shot
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x100000000))
{
int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE), (int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
damage += int32(float(base) / m_caster->GetAttackTime(RANGED_ATTACK) * 2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1f);
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Judgement of Righteousness - receive benefit from Spell Damage and Attack power
if (m_spellInfo->Id == 20187)
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
damage += int32(ap * 0.2f) + int32(holy * 32 / 100);
}
// Judgement of Vengeance/Corruption ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance/Blood Corruption on the target
else if ((classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x800000000)) && m_spellInfo->SpellIconID==2292)
{
uint32 debuf_id;
switch (m_spellInfo->Id)
{
case 53733: debuf_id = 53742; break;// Judgement of Corruption -> Blood Corruption
case 31804: debuf_id = 31803; break;// Judgement of Vengeance -> Holy Vengeance
default: return;
}
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
damage += int32(ap * 0.14f) + int32(holy * 22 / 100);
// Get stack of Holy Vengeance on the target added by caster
uint32 stacks = 0;
Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if (((*itr)->GetId() == debuf_id) && (*itr)->GetCasterGuid() == m_caster->GetObjectGuid())
{
stacks = (*itr)->GetStackAmount();
break;
}
}
// + 10% for each application of Holy Vengeance on the target
if (stacks)
damage += damage * stacks * 10 / 100;
}
// Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000004000))
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
}
// Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000008000000000))
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
}
// Hammer of the Righteous
else if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0004000000000000))
{
// Add main hand dps * effect[2] amount
float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_INDEX_2);
damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
}
// Judgement
else if (m_spellInfo->Id == 54158)
{
// [1 + 0.25 * SPH + 0.16 * AP]
damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.16f);
}
break;
}
}
if (damage >= 0)
m_damage += damage;
}
}
void Spell::EffectDummy(SpellEffectEntry const* effect)
{
if (!unitTarget && !gameObjTarget && !itemTarget)
return;
// selection by spell family
switch(m_spellInfo->GetSpellFamilyName())
{
case SPELLFAMILY_GENERIC:
{
switch (m_spellInfo->Id)
{
case 3360: // Curse of the Eye
{
if (!unitTarget)
return;
uint32 spell_id = (unitTarget->getGender() == GENDER_MALE) ? 10651 : 10653;
m_caster->CastSpell(unitTarget, spell_id, true);
return;
}
case 7671: // Transformation (human<->worgen)
{
if (!unitTarget)
return;
// Transform Visual
unitTarget->CastSpell(unitTarget, 24085, true);
return;
}
case 8063: // Deviate Fish
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 5))
{
case 1: spell_id = 8064; break; // Sleepy
case 2: spell_id = 8065; break; // Invigorate
case 3: spell_id = 8066; break; // Shrink
case 4: spell_id = 8067; break; // Party Time!
case 5: spell_id = 8068; break; // Healthy Spirit
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 8213: // Savory Deviate Delight
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 2))
{
// Flip Out - ninja
case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
// Yaaarrrr - pirate
case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 9976: // Polly Eats the E.C.A.C.
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Summon Polly Jr.
unitTarget->CastSpell(unitTarget, 9998, true);
((Creature*)unitTarget)->ForcedDespawn(100);
return;
}
case 10254: // Stone Dwarf Awaken Visual
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
// see spell 10255 (aura dummy)
m_caster->clearUnitState(UNIT_STAT_ROOT);
m_caster->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
return;
}
case 13120: // net-o-matic
{
if (!unitTarget)
return;
uint32 spell_id = 0;
uint32 roll = urand(0, 99);
if (roll < 2) // 2% for 30 sec self root (off-like chance unknown)
spell_id = 16566;
else if (roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
spell_id = 13119;
else // normal root
spell_id = 13099;
m_caster->CastSpell(unitTarget, spell_id, true, nullptr);
return;
}
case 13489:
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 14744, true);
return;
}
case 13567: // Dummy Trigger
{
// can be used for different aura triggering, so select by aura
if (!m_triggeredByAuraSpell || !unitTarget)
return;
switch (m_triggeredByAuraSpell->Id)
{
case 26467: // Persistent Shield
m_caster->CastCustomSpell(unitTarget, 26470, &damage, nullptr, nullptr, true);
break;
default:
sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u", m_triggeredByAuraSpell->Id);
break;
}
return;
}
case 14537: // Six Demon Bag
{
if (!unitTarget)
return;
Unit* newTarget = unitTarget;
uint32 spell_id = 0;
uint32 roll = urand(0, 99);
if (roll < 25) // Fireball (25% chance)
spell_id = 15662;
else if (roll < 50) // Frostbolt (25% chance)
spell_id = 11538;
else if (roll < 70) // Chain Lighting (20% chance)
spell_id = 21179;
else if (roll < 77) // Polymorph (10% chance, 7% to target)
spell_id = 14621;
else if (roll < 80) // Polymorph (10% chance, 3% to self, backfire)
{
spell_id = 14621;
newTarget = m_caster;
}
else if (roll < 95) // Enveloping Winds (15% chance)
spell_id = 25189;
else // Summon Felhund minion (5% chance)
{
spell_id = 14642;
newTarget = m_caster;
}
m_caster->CastSpell(newTarget, spell_id, true, m_CastItem);
return;
}
case 15998: // Capture Worg Pup
case 29435: // Capture Female Kaliri Hatchling
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Creature* creatureTarget = (Creature*)unitTarget;
creatureTarget->ForcedDespawn();
return;
}
case 16589: // Noggenfogger Elixir
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 3))
{
case 1: spell_id = 16595; break;
case 2: spell_id = 16593; break;
default: spell_id = 16591; break;
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 17009: // Voodoo
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(0, 6))
{
case 0: spell_id = 16707; break; // Hex
case 1: spell_id = 16708; break; // Hex
case 2: spell_id = 16709; break; // Hex
case 3: spell_id = 16711; break; // Grow
case 4: spell_id = 16712; break; // Special Brew
case 5: spell_id = 16713; break; // Ghostly
case 6: spell_id = 16716; break; // Launch
}
m_caster->CastSpell(unitTarget, spell_id, true, nullptr, nullptr, m_originalCasterGUID, m_spellInfo);
return;
}
case 17251: // Spirit Healer Res
{
if (!unitTarget)
return;
Unit* caster = GetAffectiveCaster();
if (caster && caster->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
data << unitTarget->GetObjectGuid();
((Player*)caster)->GetSession()->SendPacket(&data);
}
return;
}
case 17271: // Test Fetid Skull
{
if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = urand(0, 1)
? 17269 // Create Resonating Skull
: 17270; // Create Bone Dust
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 17770: // Wolfshead Helm Energy
{
m_caster->CastSpell(m_caster, 29940, true, nullptr);
return;
}
case 17950: // Shadow Portal
{
if (!unitTarget)
return;
// Shadow Portal
const uint32 spell_list[6] = {17863, 17939, 17943, 17944, 17946, 17948};
m_caster->CastSpell(unitTarget, spell_list[urand(0, 5)], true);
return;
}
case 19395: // Gordunni Trap
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, urand(0, 1) ? 19394 : 11756, true);
return;
}
case 19411: // Lava Bomb
case 20474: // Lava Bomb
{
if (!unitTarget)
return;
// Hack alert!
// This dummy are expected to cast spell 20494 to summon GO entry 177704
// Spell does not exist client side, so we have to make a hack, creating the GO (SPELL_EFFECT_SUMMON_OBJECT_WILD)
// Spell should appear in both SMSG_SPELL_START/GO and SMSG_SPELLLOGEXECUTE
// For later, creating custom spell
// _START: packguid: target, cast flags: 0xB, TARGET_FLAG_SELF
// _GO: packGuid: target, cast flags: 0x4309, TARGET_FLAG_DEST_LOCATION
// LOG: spell: 20494, effect, pguid: goguid
GameObject* pGameObj = new GameObject;
Map* map = unitTarget->GetMap();
if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), 177704,
map, m_caster->GetPhaseMask(),
unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(),
unitTarget->GetOrientation()))
{
delete pGameObj;
return;
}
DEBUG_LOG("Gameobject, create custom in SpellEffects.cpp EffectDummy");
// Expect created without owner, but with level from _template
pGameObj->SetRespawnTime(MINUTE / 2);
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, pGameObj->GetGOInfo()->trap.level);
pGameObj->SetSpellId(m_spellInfo->Id);
map->Add(pGameObj);
return;
}
case 19869: // Dragon Orb
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(23958))
return;
unitTarget->CastSpell(unitTarget, 19832, true);
return;
}
case 20037: // Explode Orb Effect
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 20038, true);
return;
}
case 20577: // Cannibalize
{
if (unitTarget)
m_caster->CastSpell(m_caster, 20578, false, nullptr);
return;
}
case 21147: // Arcane Vacuum
{
if (!unitTarget)
return;
// Spell used by Azuregos to teleport all the players to him
// This also resets the target threat
if (m_caster->GetThreatManager().getThreat(unitTarget))
m_caster->GetThreatManager().modifyThreatPercent(unitTarget, -100);
// cast summon player
m_caster->CastSpell(unitTarget, 21150, true);
return;
}
case 23019: // Crystal Prison Dummy DND
{
if (!unitTarget || !unitTarget->IsAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->IsPet())
return;
Creature* creatureTarget = (Creature*)unitTarget;
if (creatureTarget->IsPet())
return;
GameObject* pGameObj = new GameObject;
Map* map = creatureTarget->GetMap();
// create before death for get proper coordinates
if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
creatureTarget->GetOrientation()))
{
delete pGameObj;
return;
}
pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime() - time(nullptr));
pGameObj->SetOwnerGuid(m_caster->GetObjectGuid());
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
pGameObj->SetSpellId(m_spellInfo->Id);
creatureTarget->ForcedDespawn();
DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy");
map->Add(pGameObj);
return;
}
case 23074: // Arcanite Dragonling
{
if (!m_CastItem)
return;
m_caster->CastSpell(m_caster, 19804, true, m_CastItem);
return;
}
case 23075: // Mithril Mechanical Dragonling
{
if (!m_CastItem)
return;
m_caster->CastSpell(m_caster, 12749, true, m_CastItem);
return;
}
case 23076: // Mechanical Dragonling
{
if (!m_CastItem)
return;
m_caster->CastSpell(m_caster, 4073, true, m_CastItem);
return;
}
case 23133: // Gnomish Battle Chicken
{
if (!m_CastItem)
return;
m_caster->CastSpell(m_caster, 13166, true, m_CastItem);
return;
}
case 23138: // Gate of Shazzrah
{
if (!unitTarget)
return;
// Effect probably include a threat change, but it is unclear if fully
// reset or just forced upon target for teleport (SMSG_HIGHEST_THREAT_UPDATE)
// Gate of Shazzrah
m_caster->CastSpell(unitTarget, 23139, true);
return;
}
case 23448: // Transporter Arrival - Ultrasafe Transporter: Gadgetzan - backfires
{
int32 r = irand(0, 119);
if (r < 20) // Transporter Malfunction - 1/6 polymorph
m_caster->CastSpell(m_caster, 23444, true);
else if (r < 100) // Evil Twin - 4/6 evil twin
m_caster->CastSpell(m_caster, 23445, true);
else // Transporter Malfunction - 1/6 miss the target
m_caster->CastSpell(m_caster, 36902, true);
return;
}
case 23453: // Gnomish Transporter - Ultrasafe Transporter: Gadgetzan
{
if (roll_chance_i(50)) // Gadgetzan Transporter - success
m_caster->CastSpell(m_caster, 23441, true);
else // Gadgetzan Transporter Failure - failure
m_caster->CastSpell(m_caster, 23446, true);
return;
}
case 23645: // Hourglass Sand
m_caster->RemoveAurasDueToSpell(23170); // Brood Affliction: Bronze
return;
case 23725: // Gift of Life (warrior bwl trinket)
m_caster->CastSpell(m_caster, 23782, true);
m_caster->CastSpell(m_caster, 23783, true);
return;
case 24930: // Hallow's End Treat
{
uint32 spell_id = 0;
switch (urand(1, 4))
{
case 1: spell_id = 24924; break; // Larger and Orange
case 2: spell_id = 24925; break; // Skeleton
case 3: spell_id = 24926; break; // Pirate
case 4: spell_id = 24927; break; // Ghost
}
m_caster->CastSpell(m_caster, spell_id, true);
return;
}
case 25860: // Reindeer Transformation
{
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
return;
float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
float speed = m_caster->GetSpeedRate(MOVE_RUN);
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
// 5 different spells used depending on mounted speed and if mount can fly or not
if (flyspeed >= 4.1f)
// Flying Reindeer
m_caster->CastSpell(m_caster, 44827, true); // 310% flying Reindeer
else if (flyspeed >= 3.8f)
// Flying Reindeer
m_caster->CastSpell(m_caster, 44825, true); // 280% flying Reindeer
else if (flyspeed >= 1.6f)
// Flying Reindeer
m_caster->CastSpell(m_caster, 44824, true); // 60% flying Reindeer
else if (speed >= 2.0f)
// Reindeer
m_caster->CastSpell(m_caster, 25859, true); // 100% ground Reindeer
else
// Reindeer
m_caster->CastSpell(m_caster, 25858, true); // 60% ground Reindeer
return;
}
case 26074: // Holiday Cheer
// implemented at client side
return;
case 28006: // Arcane Cloaking
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
// Naxxramas Entry Flag Effect DND
m_caster->CastSpell(unitTarget, 29294, true);
return;
}
case 29126: // Cleansing Flames (Darnassus)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 29099, true);
return;
}
case 29135: // Cleansing Flames (Ironforge)
case 29136: // Cleansing Flames (Orgrimmar)
case 29137: // Cleansing Flames (Stormwind)
case 29138: // Cleansing Flames (Thunder Bluff)
case 29139: // Cleansing Flames (Undercity)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spellIDs[] = {29102, 29130, 29101, 29132, 29133};
unitTarget->CastSpell(unitTarget, spellIDs[m_spellInfo->Id - 29135], true);
return;
}
case 29200: // Purify Helboar Meat
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = roll_chance_i(50)
? 29277 // Summon Purified Helboar Meat
: 29278; // Summon Toxic Helboar Meat
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 29858: // Soulshatter
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
m_caster->CastSpell(unitTarget, 32835, true);
return;
}
case 29969: // Summon Blizzard
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 29952, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 29979: // Massive Magnetic Pull
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 30010, true);
return;
}
case 30004: // Flame Wreath
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 29946, true);
return;
}
case 30458: // Nigh Invulnerability
{
if (!m_CastItem)
return;
if (roll_chance_i(86)) // Nigh-Invulnerability - success
m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
else // Complete Vulnerability - backfire in 14% casts
m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
return;
}
case 30507: // Poultryizer
{
if (!m_CastItem)
return;
if (roll_chance_i(80)) // Poultryized! - success
m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
else // Poultryized! - backfire 20%
m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
return;
}
case 32027: // Expedition Flare
{
// 32029 = Expedition Preserver | 32030 = Expedition Scout
m_caster->CastSpell(m_caster, (urand(0, 1) ? 32029 : 32030), true);
return;
}
case 32146: // Liquid Fire
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
((Creature*)unitTarget)->ForcedDespawn();
return;
}
case 32300: // Focus Fire
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, unitTarget->GetMap()->IsRegularDifficulty() ? 32302 : 38382, true);
return;
}
case 32312: // Move 1 (Chess event AI short distance move)
case 37388: // Move 2 (Chess event AI long distance move)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// cast generic move spell
m_caster->CastSpell(unitTarget, 30012, true);
return;
}
case 33060: // Make a Wish
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 5))
{
case 1: spell_id = 33053; break; // Mr Pinchy's Blessing
case 2: spell_id = 33057; break; // Summon Mighty Mr. Pinchy
case 3: spell_id = 33059; break; // Summon Furious Mr. Pinchy
case 4: spell_id = 33062; break; // Tiny Magical Crawdad
case 5: spell_id = 33064; break; // Mr. Pinchy's Gift
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 34803: // Summon Reinforcements
{
m_caster->CastSpell(m_caster, 34810, true); // Summon 20083 behind of the caster
m_caster->CastSpell(m_caster, 34817, true); // Summon 20078 right of the caster
m_caster->CastSpell(m_caster, 34818, true); // Summon 20078 left of the caster
m_caster->CastSpell(m_caster, 34819, true); // Summon 20078 front of the caster
return;
}
case 36677: // Chaos Breath
{
if (!unitTarget)
return;
uint32 possibleSpells[] = {36693, 36694, 36695, 36696, 36697, 36698, 36699, 36700} ;
std::vector<uint32> spellPool(possibleSpells, possibleSpells + countof(possibleSpells));
std::random_shuffle(spellPool.begin(), spellPool.end());
for (uint8 i = 0; i < (m_caster->GetMap()->IsRegularDifficulty() ? 2 : 4); ++i)
m_caster->CastSpell(m_caster, spellPool[i], true);
return;
}
case 33923: // Sonic Boom
case 38796: // Sonic Boom (heroic)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, m_spellInfo->Id == 33923 ? 33666 : 38795, true);
return;
}
case 35745: // Socrethar's Stone
{
uint32 spell_id;
switch (m_caster->GetAreaId())
{
case 3900: spell_id = 35743; break; // Socrethar Portal
case 3742: spell_id = 35744; break; // Socrethar Portal
default: return;
}
m_caster->CastSpell(m_caster, spell_id, true);
return;
}
case 37674: // Chaos Blast
{
if (!unitTarget)
return;
int32 basepoints0 = 100;
m_caster->CastCustomSpell(unitTarget, 37675, &basepoints0, nullptr, nullptr, true);
return;
}
case 39189: // Sha'tari Torch
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Flames
if (unitTarget->HasAura(39199))
return;
unitTarget->CastSpell(unitTarget, 39199, true);
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
((Creature*)unitTarget)->ForcedDespawn(10000);
return;
}
case 39635: // Throw Glaive (first)
case 39849: // Throw Glaive (second)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 41466, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
{
// selecting one from Bloodstained Fortune item
uint32 newitemid;
switch (urand(1, 20))
{
case 1: newitemid = 32688; break;
case 2: newitemid = 32689; break;
case 3: newitemid = 32690; break;
case 4: newitemid = 32691; break;
case 5: newitemid = 32692; break;
case 6: newitemid = 32693; break;
case 7: newitemid = 32700; break;
case 8: newitemid = 32701; break;
case 9: newitemid = 32702; break;
case 10: newitemid = 32703; break;
case 11: newitemid = 32704; break;
case 12: newitemid = 32705; break;
case 13: newitemid = 32706; break;
case 14: newitemid = 32707; break;
case 15: newitemid = 32708; break;
case 16: newitemid = 32709; break;
case 17: newitemid = 32710; break;
case 18: newitemid = 32711; break;
case 19: newitemid = 32712; break;
case 20: newitemid = 32713; break;
default:
return;
}
DoCreateItem(effect, newitemid);
return;
}
case 40834: // Agonizing Flames
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 40932, true);
return;
}
case 40869: // Fatal Attraction
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 41001, true);
return;
}
case 40962: // Blade's Edge Terrace Demon Boss Summon Branch
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 4))
{
case 1: spell_id = 40957; break; // Blade's Edge Terrace Demon Boss Summon 1
case 2: spell_id = 40959; break; // Blade's Edge Terrace Demon Boss Summon 2
case 3: spell_id = 40960; break; // Blade's Edge Terrace Demon Boss Summon 3
case 4: spell_id = 40961; break; // Blade's Edge Terrace Demon Boss Summon 4
}
unitTarget->CastSpell(unitTarget, spell_id, true);
return;
}
case 41283: // Abyssal Toss
{
if (!unitTarget)
return;
m_caster->SummonCreature(23416, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
return;
}
case 41333: // Empyreal Equivalency
{
if (!unitTarget)
return;
// Equilize the health of all targets based on the corresponding health percent
float health_diff = (float)unitTarget->GetMaxHealth() / (float)m_caster->GetMaxHealth();
unitTarget->SetHealth(m_caster->GetHealth() * health_diff);
return;
}
case 42287: // Salvage Wreckage
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (roll_chance_i(66))
m_caster->CastSpell(m_caster, 42289, true, m_CastItem);
else
m_caster->CastSpell(m_caster, 42288, true);
return;
}
case 42485: // End of Ooze Channel
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->CastSpell(m_caster, 42486, true);
// There is no known spell to kill the target
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
return;
}
case 42489: // Cast Ooze Zap When Energized
{
// only process first effect
// the logic is described by spell 42488 - Caster Spell 1 Only if Aura 2 Is On Caster (not used here)
if (effect->EffectIndex != EFFECT_INDEX_0)
return;
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !m_caster->HasAura(m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1)))
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
((Creature*)unitTarget)->AI()->AttackStart(m_caster);
return;
}
case 42628: // Fire Bomb (throw)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 42629, true);
return;
}
case 42631: // Fire Bomb (explode)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->RemoveAurasDueToSpell(42629);
unitTarget->CastSpell(unitTarget, 42630, true);
// despawn the bomb after exploding
((Creature*)unitTarget)->ForcedDespawn(3000);
return;
}
case 42793: // Burn Body
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Creature* pCreature = (Creature*)unitTarget;
// Spell can be used in combat and may affect different target than the expected.
// If target is not the expected we need to prevent this effect.
if (pCreature->HasLootRecipient() || pCreature->IsInCombat())
return;
// set loot recipient, prevent re-use same target
pCreature->SetLootRecipient(m_caster);
pCreature->ForcedDespawn(m_duration);
// EFFECT_INDEX_2 has 0 miscvalue for effect 134, doing the killcredit here instead (only one known case exist where 0)
((Player*)m_caster)->KilledMonster(pCreature->GetCreatureInfo(), pCreature->GetObjectGuid());
return;
}
case 43014: // Despawn Self
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
((Creature*)m_caster)->ForcedDespawn();
return;
}
case 43036: // Dismembering Corpse
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (unitTarget->HasAura(43059, EFFECT_INDEX_0))
return;
unitTarget->CastSpell(m_caster, 43037, true);
unitTarget->CastSpell(unitTarget, 43059, true);
return;
}
case 43069: // Towers of Certain Doom: Skorn Cannonfire
{
// Towers of Certain Doom: Tower Caster Instakill
m_caster->CastSpell(m_caster, 43072, true);
return;
}
case 43096: // Summon All Players
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 43097, true);
return;
}
case 43144: // Hatch All Eggs
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 42493, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 43209: // Place Ram Meat
{
if (!unitTarget)
return;
// Self Visual - Sleep Until Cancelled (DND)
unitTarget->RemoveAurasDueToSpell(6606);
return;
}
case 43498: // Siphon Soul
{
// This spell should cast the next spell only for one (player)target, however it should hit multiple targets, hence this kind of implementation
if (!unitTarget || m_UniqueTargetInfo.rbegin()->targetGUID != unitTarget->GetObjectGuid())
return;
std::vector<Unit*> possibleTargets;
possibleTargets.reserve(m_UniqueTargetInfo.size());
for (TargetList::const_iterator itr = m_UniqueTargetInfo.begin(); itr != m_UniqueTargetInfo.end(); ++itr)
{
// Skip Non-Players
if (!itr->targetGUID.IsPlayer())
continue;
if (Unit* target = m_caster->GetMap()->GetPlayer(itr->targetGUID))
possibleTargets.push_back(target);
}
// Cast Siphon Soul channeling spell
if (!possibleTargets.empty())
m_caster->CastSpell(possibleTargets[urand(0, possibleTargets.size() - 1)], 43501, false);
return;
}
case 43572: // Send Them Packing: On /Raise Emote Dummy to Player
{
if (!unitTarget)
return;
// m_caster (creature) should start walking back to it's "home" here, no clear way how to do that
// Send Them Packing: On Successful Dummy Spell Kill Credit
m_caster->CastSpell(unitTarget, 42721, true);
return;
}
// Demon Broiled Surprise
case 43723:
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)m_caster)->CastSpell(unitTarget, 43753, true, m_CastItem, nullptr, m_originalCasterGUID, m_spellInfo);
return;
}
case 43882: // Scourging Crystal Controller Dummy
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// see spell dummy 50133
unitTarget->RemoveAurasDueToSpell(43874);
return;
}
case 44454: // Tasty Reef Fish
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
m_caster->CastSpell(unitTarget, 44455, true, m_CastItem);
return;
}
case 44869: // Spectral Blast
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// If target has spectral exhaustion or spectral realm aura return
if (unitTarget->HasAura(44867) || unitTarget->HasAura(46021))
return;
// Cast the spectral realm effect spell, visual spell and spectral blast rift summoning
unitTarget->CastSpell(unitTarget, 44866, true, nullptr, nullptr, m_caster->GetObjectGuid());
unitTarget->CastSpell(unitTarget, 46648, true, nullptr, nullptr, m_caster->GetObjectGuid());
unitTarget->CastSpell(unitTarget, 44811, true);
return;
}
case 44875: // Complete Raptor Capture
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Creature* creatureTarget = (Creature*)unitTarget;
creatureTarget->ForcedDespawn();
// cast spell Raptor Capture Credit
m_caster->CastSpell(m_caster, 42337, true, nullptr);
return;
}
case 44997: // Converting Sentry
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Creature* creatureTarget = (Creature*)unitTarget;
creatureTarget->ForcedDespawn();
// Converted Sentry Credit
m_caster->CastSpell(m_caster, 45009, true);
return;
}
case 45030: // Impale Emissary
{
// Emissary of Hate Credit
m_caster->CastSpell(m_caster, 45088, true);
return;
}
case 45449: // Arcane Prisoner Rescue
{
uint32 spellId = 0;
switch (rand() % 2)
{
case 0: spellId = 45446; break; // Summon Arcane Prisoner - Male
case 1: spellId = 45448; break; // Summon Arcane Prisoner - Female
}
// Spawn
m_caster->CastSpell(m_caster, spellId, true);
if (!unitTarget) return;
// Arcane Prisoner Kill Credit
unitTarget->CastSpell(m_caster, 45456, true);
break;
}
case 45583: // Throw Gnomish Grenade
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
// look for gameobject within max spell range of unitTarget, and respawn if found
// big fire
GameObject* pGo = nullptr;
float fMaxDist = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
MaNGOS::NearestGameObjectEntryInPosRangeCheck go_check_big(*unitTarget, 187675, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), fMaxDist);
MaNGOS::GameObjectSearcher<MaNGOS::NearestGameObjectEntryInPosRangeCheck> checker1(pGo, go_check_big);
Cell::VisitGridObjects(unitTarget, checker1, fMaxDist);
if (pGo && !pGo->isSpawned())
{
pGo->SetRespawnTime(MINUTE / 2);
pGo->Refresh();
}
// small fire
std::list<GameObject*> lList;
MaNGOS::GameObjectEntryInPosRangeCheck go_check_small(*unitTarget, 187676, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), fMaxDist);
MaNGOS::GameObjectListSearcher<MaNGOS::GameObjectEntryInPosRangeCheck> checker2(lList, go_check_small);
Cell::VisitGridObjects(unitTarget, checker2, fMaxDist);
for (std::list<GameObject*>::iterator iter = lList.begin(); iter != lList.end(); ++iter)
{
if (!(*iter)->isSpawned())
{
(*iter)->SetRespawnTime(MINUTE / 2);
(*iter)->Refresh();
}
}
return;
}
case 45685: // Magnataur On Death 2
{
m_caster->RemoveAurasDueToSpell(45673);
m_caster->RemoveAurasDueToSpell(45672);
m_caster->RemoveAurasDueToSpell(45677);
m_caster->RemoveAurasDueToSpell(45681);
m_caster->RemoveAurasDueToSpell(45683);
return;
}
case 45958: // Signal Alliance
{
m_caster->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 45976: // Open Portal
case 46177: // Open All Portals
{
if (!unitTarget)
return;
// portal visual
unitTarget->CastSpell(unitTarget, 45977, true);
// break in case additional procressing in scripting library required
break;
}
case 45980: // Re-Cursive Transmatter Injection
{
if (m_caster->GetTypeId() == TYPEID_PLAYER && unitTarget)
{
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(46022))
{
m_caster->CastSpell(unitTarget, pSpell, true);
SpellEffectEntry const* killSpellEffect = pSpell->GetSpellEffect(EFFECT_INDEX_0);
((Player*)m_caster)->KilledMonsterCredit(killSpellEffect ? killSpellEffect->EffectMiscValue : 0);
}
if (unitTarget->GetTypeId() == TYPEID_UNIT)
((Creature*)unitTarget)->ForcedDespawn();
}
return;
}
case 45989: // Summon Void Sentinel Summoner Visual
{
if (!unitTarget)
return;
// summon void sentinel
unitTarget->CastSpell(unitTarget, 45988, true);
return;
}
case 45990: // Collect Oil
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(45991))
{
unitTarget->CastSpell(unitTarget, pSpell, true);
((Creature*)unitTarget)->ForcedDespawn(m_duration);
}
return;
}
case 46167: // Planning for the Future: Create Snowfall Glade Pup Cover
case 50918: // Gluttonous Lurkers: Create Basilisk Crystals Cover
case 50926: // Gluttonous Lurkers: Create Zul'Drak Rat Cover
case 51026: // Create Drakkari Medallion Cover
case 51592: // Pickup Primordial Hatchling
case 51961: // Captured Chicken Cover
case 55364: // Create Ghoul Drool Cover
case 61832: // Rifle the Bodies: Create Magehunter Personal Effects Cover
case 63125: // Search Maloric
case 74904: // Pickup Sen'jin Frog
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spellId = 0;
switch (m_spellInfo->Id)
{
case 46167: spellId = 46773; break;
case 50918: spellId = 50919; break;
case 50926: spellId = 50927; break;
case 51026: spellId = 50737; break;
case 51592: spellId = 51593; break;
case 51961: spellId = 51037; break;
case 55364: spellId = 55363; break;
case 61832: spellId = 47096; break;
case 63125: spellId = 63126; break;
case 74904: spellId = 74905; break;
}
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(spellId))
{
unitTarget->CastSpell(m_caster, spellId, true);
Creature* creatureTarget = (Creature*)unitTarget;
if (const SpellCastTimesEntry* pCastTime = sSpellCastTimesStore.LookupEntry(pSpell->CastingTimeIndex))
creatureTarget->ForcedDespawn(pCastTime->CastTime + 1);
}
return;
}
case 46171: // Scuttle Wrecked Flying Machine
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
// look for gameobject within max spell range of unitTarget, and respawn if found
GameObject* pGo = nullptr;
float fMaxDist = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
MaNGOS::NearestGameObjectEntryInPosRangeCheck go_check(*unitTarget, 187675, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), fMaxDist);
MaNGOS::GameObjectSearcher<MaNGOS::NearestGameObjectEntryInPosRangeCheck> checker(pGo, go_check);
Cell::VisitGridObjects(unitTarget, checker, fMaxDist);
if (pGo && !pGo->isSpawned())
{
pGo->SetRespawnTime(MINUTE / 2);
pGo->Refresh();
}
return;
}
case 46292: // Cataclysm Breath
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spellId = 0;
switch (urand(0, 7))
{
case 0: spellId = 46293; break; // Corrosive Poison
case 1: spellId = 46294; break; // Fevered Fatigue
case 2: spellId = 46295; break; // Hex
case 3: spellId = 46296; break; // Necrotic Poison
case 4: spellId = 46297; break; // Piercing Shadow
case 5: spellId = 46298; break; // Shrink
case 6: spellId = 46299; break; // Wavering Will
case 7: spellId = 46300; break; // Withered Touch
}
m_caster->CastSpell(unitTarget, spellId, true);
return;
}
case 46372: // Ice Spear Target Picker
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 46359, true);
return;
}
case 46485: // Greatmother's Soulcatcher
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(46486))
{
m_caster->CastSpell(unitTarget, pSpell, true);
if (SpellEffectEntry const* pSpellEffect = pSpell->GetSpellEffect(EFFECT_INDEX_0))
if (const SpellEntry *pSpellCredit = sSpellStore.LookupEntry(pSpellEffect->EffectTriggerSpell))
if(SpellEffectEntry const* pSpellCreditEffect = pSpellCredit->GetSpellEffect(EFFECT_INDEX_0))
((Player*)m_caster)->KilledMonsterCredit(pSpellCreditEffect->EffectMiscValue);
((Creature*)unitTarget)->ForcedDespawn();
}
return;
}
case 46606: // Plague Canister Dummy
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->CastSpell(m_caster, 43160, true);
unitTarget->SetDeathState(JUST_DIED);
unitTarget->SetHealth(0);
return;
}
case 46671: // Cleansing Flames (Exodar)
case 46672: // Cleansing Flames (Silvermoon)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, m_spellInfo->Id == 46671 ? 46690 : 46689, true);
return;
}
case 46797: // Quest - Borean Tundra - Set Explosives Cart
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
// Quest - Borean Tundra - Summon Explosives Cart
unitTarget->CastSpell(unitTarget, 46798, true);
return;
}
case 47110: // Summon Drakuru's Image
{
uint32 spellId = 0;
// Spell 47117,47149,47316,47405,50439 exist, are these used to check area/meet requirement
// and to cast correct spell in correct area?
switch (m_caster->GetAreaId())
{
case 4255: spellId = 47381; break; // Reagent Check (Frozen Mojo)
case 4209: spellId = 47386; break; // Reagent Check (Zim'Bo's Mojo)
case 4270: spellId = 47389; break; // Reagent Check (Desperate Mojo)
case 4216: spellId = 47408; break; // Reagent Check (Sacred Mojo)
case 4196: spellId = 50441; break; // Reagent Check (Survival Mojo)
}
// The additional castspell arguments are needed here to remove reagents for triggered spells
if (spellId)
m_caster->CastSpell(m_caster, spellId, true, m_CastItem, nullptr, m_caster->GetObjectGuid(), m_spellInfo);
return;
}
case 47170: // Impale Leviroth
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->SetHealthPercent(8.0f);
// Cosmetic - Underwater Blood (no sound)
unitTarget->CastSpell(unitTarget, 47172, true);
((Creature*)unitTarget)->AI()->AttackStart(m_caster);
return;
}
case 47176: // Infect Ice Troll
{
// Spell has wrong areaGroupid, so it can not be casted where expected.
// TODO: research if spells casted by NPC, having TARGET_SCRIPT, can have disabled area check
if (!unitTarget)
return;
// Plague Effect Self
unitTarget->CastSpell(unitTarget, 47178, true);
return;
}
case 47305: // Potent Explosive Charge
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// only if below 80% hp
if (unitTarget->GetHealthPercent() > 80.0f)
return;
// Issues with explosion animation (remove insta kill spell resolves the issue)
// Quest - Jormungar Explosion Spell Spawner
unitTarget->CastSpell(unitTarget, 47311, true);
// Potent Explosive Charge
unitTarget->CastSpell(unitTarget, 47306, true);
return;
}
case 47381: // Reagent Check (Frozen Mojo)
case 47386: // Reagent Check (Zim'Bo's Mojo)
case 47389: // Reagent Check (Desperate Mojo)
case 47408: // Reagent Check (Sacred Mojo)
case 50441: // Reagent Check (Survival Mojo)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
switch (m_spellInfo->Id)
{
case 47381:
// Envision Drakuru
m_caster->CastSpell(m_caster, 47118, true);
break;
case 47386:
m_caster->CastSpell(m_caster, 47150, true);
break;
case 47389:
m_caster->CastSpell(m_caster, 47317, true);
break;
case 47408:
m_caster->CastSpell(m_caster, 47406, true);
break;
case 50441:
m_caster->CastSpell(m_caster, 50440, true);
break;
}
return;
}
case 48046: // Use Camera
{
if (!unitTarget)
return;
// No despawn expected, nor any change in dynamic flags/other flags.
// Need internal way to track if credit has been given for this object.
// Iron Dwarf Snapshot Credit
m_caster->CastSpell(m_caster, 48047, true, m_CastItem, nullptr, unitTarget->GetObjectGuid());
return;
}
case 48790: // Neltharion's Flame
{
if (!unitTarget)
return;
// Neltharion's Flame Fire Bunny: Periodic Fire Aura
unitTarget->CastSpell(unitTarget, 48786, false);
return;
}
case 49357: // Brewfest Mount Transformation
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
return;
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
// Ram for Alliance, Kodo for Horde
if (((Player*)m_caster)->GetTeam() == ALLIANCE)
{
if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
// 100% Ram
m_caster->CastSpell(m_caster, 43900, true);
else
// 60% Ram
m_caster->CastSpell(m_caster, 43899, true);
}
else
{
if (((Player*)m_caster)->GetSpeedRate(MOVE_RUN) >= 2.0f)
// 100% Kodo
m_caster->CastSpell(m_caster, 49379, true);
else
// 60% Kodo
m_caster->CastSpell(m_caster, 49378, true);
}
return;
}
case 49634: // Sergeant's Flare
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Towers of Certain Doom: Tower Bunny Smoke Flare Effect
// TODO: MaNGOS::DynamicObjectUpdater::VisitHelper prevent aura to be applied to dummy creature (see HandleAuraDummy for effect of aura)
m_caster->CastSpell(unitTarget, 56511, true);
static uint32 const spellCredit[4] =
{
43077, // E Kill Credit
43067, // NW Kill Credit
43087, // SE Kill Credit
43086, // SW Kill Credit
};
// for sizeof(spellCredit)
for (int i = 0; i < 4; ++i)
{
const SpellEntry* pSpell = sSpellStore.LookupEntry(spellCredit[i]);
if (pSpell->GetEffectMiscValue(EFFECT_INDEX_0) == unitTarget->GetEntry())
{
m_caster->CastSpell(m_caster, spellCredit[i], true);
break;
}
}
return;
}
case 49859: // Rune of Command
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Captive Stone Giant Kill Credit
unitTarget->CastSpell(m_caster, 43564, true);
// Is it supposed to despawn?
((Creature*)unitTarget)->ForcedDespawn();
return;
}
case 50133: // Scourging Crystal Controller
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Scourge Mur'gul Camp: Force Shield Arcane Purple x3
if (unitTarget->HasAura(43874))
{
// someone else is already channeling target
if (unitTarget->HasAura(43878))
return;
// Scourging Crystal Controller
m_caster->CastSpell(unitTarget, 43878, true, m_CastItem);
}
return;
}
case 50243: // Teach Language
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// spell has a 1/3 chance to trigger one of the below
if (roll_chance_i(66))
return;
if (((Player*)m_caster)->GetTeam() == ALLIANCE)
{
// 1000001 - gnomish binary
m_caster->CastSpell(m_caster, 50242, true);
}
else
{
// 01001000 - goblin binary
m_caster->CastSpell(m_caster, 50246, true);
}
return;
}
case 50440: // Envision Drakuru
{
if (!unitTarget)
return;
// Script Cast Summon Image of Drakuru 05
unitTarget->CastSpell(unitTarget, 50439, true);
return;
}
case 50546: // Ley Line Focus Control Ring Effect
case 50547: // Ley Line Focus Control Amulet Effect
case 50548: // Ley Line Focus Control Talisman Effect
{
if (!m_originalCaster || !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
switch (m_spellInfo->Id)
{
case 50546: unitTarget->CastSpell(m_originalCaster, 47390, true); break;
case 50547: unitTarget->CastSpell(m_originalCaster, 47472, true); break;
case 50548: unitTarget->CastSpell(m_originalCaster, 47635, true); break;
}
return;
}
case 51276: // Incinerate Corpse
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->CastSpell(unitTarget, 51278, true);
unitTarget->CastSpell(m_caster, 51279, true);
unitTarget->SetDeathState(JUST_DIED);
return;
}
case 51330: // Shoot RJR
{
if (!unitTarget)
return;
// guessed chances
if (roll_chance_i(75))
m_caster->CastSpell(unitTarget, roll_chance_i(50) ? 51332 : 51366, true, m_CastItem);
else
m_caster->CastSpell(unitTarget, 51331, true, m_CastItem);
return;
}
case 51333: // Dig For Treasure
{
if (!unitTarget)
return;
if (roll_chance_i(75))
m_caster->CastSpell(unitTarget, 51370, true, m_CastItem);
else
m_caster->CastSpell(m_caster, 51345, true);
return;
}
case 51336: // Magic Pull
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 50770, true);
return;
}
case 51420: // Digging for Treasure Ping
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// only spell related protector pets exist currently
Pet* pPet = m_caster->GetProtectorPet();
if (!pPet)
return;
pPet->SetFacingToObject(unitTarget);
// Digging for Treasure
pPet->CastSpell(unitTarget, 51405, true);
((Creature*)unitTarget)->ForcedDespawn(1);
return;
}
case 51582: // Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
bg->EventPlayerDroppedFlag((Player*)m_caster);
m_caster->CastSpell(m_caster, 30452, true, nullptr);
return;
}
case 51840: // Despawn Fruit Tosser
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (roll_chance_i(20))
{
// summon NPC, or...
unitTarget->CastSpell(m_caster, 52070, true);
}
else
{
// ...drop banana, orange or papaya
switch (urand(0, 2))
{
case 0: unitTarget->CastSpell(m_caster, 51836, true); break;
case 1: unitTarget->CastSpell(m_caster, 51837, true); break;
case 2: unitTarget->CastSpell(m_caster, 51839, true); break;
}
}
((Creature*)unitTarget)->ForcedDespawn(5000);
return;
}
case 51866: // Kick Nass
{
// It is possible that Nass Heartbeat (spell id 61438) is involved in this
// If so, unclear how it should work and using the below instead (even though it could be a bit hack-ish)
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Only own guardian pet
if (m_caster != unitTarget->GetOwner())
return;
// This means we already set state (see below) and need to wait.
if (unitTarget->hasUnitState(UNIT_STAT_ROOT))
return;
// Expecting pTargetDummy to be summoned by AI at death of target creatures.
Creature* pTargetDummy = nullptr;
float fRange = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, 28523, true, false, fRange * 2);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pTargetDummy, u_check);
Cell::VisitGridObjects(m_caster, searcher, fRange * 2);
if (pTargetDummy)
{
if (unitTarget->hasUnitState(UNIT_STAT_FOLLOW | UNIT_STAT_FOLLOW_MOVE))
unitTarget->GetMotionMaster()->MovementExpired();
unitTarget->MonsterMoveWithSpeed(pTargetDummy->GetPositionX(), pTargetDummy->GetPositionY(), pTargetDummy->GetPositionZ(), 24.f);
// Add state to temporarily prevent follow
unitTarget->addUnitState(UNIT_STAT_ROOT);
// Collect Hair Sample
unitTarget->CastSpell(pTargetDummy, 51870, true);
}
return;
}
case 51872: // Hair Sample Collected
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// clear state to allow follow again
m_caster->clearUnitState(UNIT_STAT_ROOT);
// Nass Kill Credit
m_caster->CastSpell(m_caster, 51871, true);
// Despawn dummy creature
((Creature*)unitTarget)->ForcedDespawn();
return;
}
case 51964: // Tormentor's Incense
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// This might not be the best way, and effect may need some adjustment. Removal of any aura from surrounding dummy creatures?
if (((Creature*)unitTarget)->AI())
((Creature*)unitTarget)->AI()->AttackStart(m_caster);
return;
}
case 51858: // Siphon of Acherus
{
if (!m_originalCaster || !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (Player* pPlayer = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself())
pPlayer->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
return;
}
case 52308: // Take Sputum Sample
{
switch(effect->EffectIndex)
{
case EFFECT_INDEX_0:
{
uint32 spellID = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_0);
uint32 reqAuraID = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1);
if (m_caster->HasAura(reqAuraID, EFFECT_INDEX_0))
m_caster->CastSpell(m_caster, spellID, true, nullptr);
return;
}
case EFFECT_INDEX_1: // additional data for dummy[0]
case EFFECT_INDEX_2:
return;
}
return;
}
case 52369: // Detonate Explosives
case 52371: // Detonate Explosives
{
if (!unitTarget)
return;
// Cosmetic - Explosion
unitTarget->CastSpell(unitTarget, 46419, true);
// look for gameobjects within max spell range of unitTarget, and respawn if found
std::list<GameObject*> lList;
float fMaxDist = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
MaNGOS::GameObjectEntryInPosRangeCheck go_check(*unitTarget, 182071, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), fMaxDist);
MaNGOS::GameObjectListSearcher<MaNGOS::GameObjectEntryInPosRangeCheck> checker(lList, go_check);
Cell::VisitGridObjects(unitTarget, checker, fMaxDist);
for (std::list<GameObject*>::iterator iter = lList.begin(); iter != lList.end(); ++iter)
{
if (!(*iter)->isSpawned())
{
(*iter)->SetRespawnTime(MINUTE / 2);
(*iter)->Refresh();
}
}
return;
}
case 52759: // Ancestral Awakening
{
if (!unitTarget)
return;
m_caster->CastCustomSpell(unitTarget, 52752, &damage, nullptr, nullptr, true);
return;
}
case 52845: // Brewfest Mount Transformation (Faction Swap)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
return;
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
// Ram for Horde, Kodo for Alliance
if (((Player*)m_caster)->GetTeam() == HORDE)
{
if (m_caster->GetSpeedRate(MOVE_RUN) >= 2.0f)
// Swift Brewfest Ram, 100% Ram
m_caster->CastSpell(m_caster, 43900, true);
else
// Brewfest Ram, 60% Ram
m_caster->CastSpell(m_caster, 43899, true);
}
else
{
if (((Player*)m_caster)->GetSpeedRate(MOVE_RUN) >= 2.0f)
// Great Brewfest Kodo, 100% Kodo
m_caster->CastSpell(m_caster, 49379, true);
else
// Brewfest Riding Kodo, 60% Kodo
m_caster->CastSpell(m_caster, 49378, true);
}
return;
}
case 53341: // Rune of Cinderglacier
case 53343: // Rune of Razorice
{
// Runeforging Credit
m_caster->CastSpell(m_caster, 54586, true);
return;
}
case 53475: // Set Oracle Faction Friendly
case 53487: // Set Wolvar Faction Honored
case 54015: // Set Oracle Faction Honored
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (effect->EffectIndex == EFFECT_INDEX_0)
{
Player* pPlayer = (Player*)m_caster;
uint32 faction_id = m_currentBasePoints[effect->EffectIndex];
int32 rep_change = m_currentBasePoints[EFFECT_INDEX_1];
FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
if (!factionEntry)
return;
// Set rep to baserep + basepoints (expecting spillover for oposite faction -> become hated)
// Not when player already has equal or higher rep with this faction
if (pPlayer->GetReputationMgr().GetBaseReputation(factionEntry) < rep_change)
pPlayer->GetReputationMgr().SetReputation(factionEntry, rep_change);
// EFFECT_INDEX_2 most likely update at war state, we already handle this in SetReputation
}
return;
}
case 53808: // Pygmy Oil
{
const uint32 spellShrink = 53805;
const uint32 spellTransf = 53806;
if (SpellAuraHolder* holder = m_caster->GetSpellAuraHolder(spellShrink))
{
// chance to become pygmified (5, 10, 15 etc)
if (roll_chance_i(holder->GetStackAmount() * 5))
{
m_caster->RemoveAurasDueToSpell(spellShrink);
m_caster->CastSpell(m_caster, spellTransf, true);
return;
}
}
if (m_caster->HasAura(spellTransf))
return;
m_caster->CastSpell(m_caster, spellShrink, true);
return;
}
case 54577: // Throw U.D.E.D.
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Sometimes issues with explosion animation. Unclear why
// but possibly caused by the order of spells.
// Permanent Feign Death
unitTarget->CastSpell(unitTarget, 29266, true);
// need to despawn later
((Creature*)unitTarget)->ForcedDespawn(2000);
// Mammoth Explosion Spell Spawner
unitTarget->CastSpell(unitTarget, 54581, true, m_CastItem);
return;
}
case 54850: // Emerge
{
// Cast Emerge summon
m_caster->CastSpell(m_caster, 54851, true);
return;
}
case 54092: // Monster Slayer's Kit
{
if (!unitTarget)
return;
uint32 spellIds[] = {51853, 54063, 54071, 54086};
m_caster->CastSpell(unitTarget, spellIds[urand(0, 3)], true);
return;
}
case 55004: // Nitro Boosts
{
if (!m_CastItem)
return;
if (roll_chance_i(95)) // Nitro Boosts - success
m_caster->CastSpell(m_caster, 54861, true, m_CastItem);
else // Knocked Up - backfire 5%
m_caster->CastSpell(m_caster, 46014, true, m_CastItem);
return;
}
case 55818: // Hurl Boulder
{
// unclear how many summon min/max random, best guess below
uint32 random = urand(3, 5);
for (uint32 i = 0; i < random; ++i)
m_caster->CastSpell(m_caster, 55528, true);
return;
}
case 56430: // Arcane Bomb
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 56431, true, nullptr, nullptr, m_caster->GetObjectGuid());
unitTarget->CastSpell(unitTarget, 56432, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 57578: // Lava Strike
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 57908: // Stain Cloth
{
// nothing do more
finish();
m_caster->CastSpell(m_caster, 57915, false, m_CastItem);
// cast item deleted
ClearCastItem();
break;
}
case 58418: // Portal to Orgrimmar
case 58420: // Portal to Stormwind
return; // implemented in EffectScript[0]
case 58601: // Remove Flight Auras
{
m_caster->RemoveSpellsCausingAura(SPELL_AURA_FLY);
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED);
return;
}
case 59640: // Underbelly Elixir
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 3))
{
case 1: spell_id = 59645; break;
case 2: spell_id = 59831; break;
case 3: spell_id = 59843; break;
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 60932: // Disengage (one from creature versions)
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 60934, true, nullptr);
return;
}
case 62105: // To'kini's Blowgun
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// Sleeping Sleep
unitTarget->CastSpell(unitTarget, 62248, true);
// Although not really correct, it's needed to have access to m_caster later,
// to properly process spell 62110 (cast from gossip).
// Can possibly be replaced with a similar function that doesn't set any dynamic flags.
((Creature*)unitTarget)->SetLootRecipient(m_caster);
unitTarget->setFaction(190); // Ambient (neutral)
unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
return;
}
case 62278: // Lightning Orb Charger
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 62466, true);
unitTarget->CastSpell(unitTarget, 62279, true);
return;
}
case 62652: // Tidal Wave
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 62653 : 62935, true);
return;
}
case 62797: // Storm Cloud
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 65123 : 65133, true);
return;
}
case 62907: // Freya's Ward
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 5; ++i)
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 63030: // Boil Ominously
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 63031, true);
return;
}
case 63499: // Dispel Magic
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 63545: // Icicle
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 63744: // Sara's Anger
case 63745: // Sara's Blessing
case 63747: // Sara's Fervor
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 63984: // Hate to Zero
{
if (!unitTarget)
return;
if (m_caster->GetThreatManager().getThreat(unitTarget))
m_caster->GetThreatManager().modifyThreatPercent(unitTarget, -100);
return;
}
case 64172: // Titanic Storm
{
if (!unitTarget || !unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
// There is no known spell to kill the target
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
return;
}
case 64385: // Spinning (from Unusual Compass)
{
m_caster->SetFacingTo(frand(0, M_PI_F * 2));
return;
}
case 64402: // Rocket Strike
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 63681, true);
return;
}
case 64489: // Feral Rush
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 64496, true);
return;
}
case 64543: // Melt Ice
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
m_caster->CastSpell(m_caster, 64540, true);
return;
}
case 64555: // Insane Periodic
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(63050) || unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
m_caster->CastSpell(unitTarget, 64464, true);
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 64673: // Feral Rush (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 64674, true);
return;
}
case 64981: // Summon Random Vanquished Tentacle
{
uint32 spell_id = 0;
switch (urand(0, 2))
{
case 0: spell_id = 64982; break; // Summon Vanquished Crusher Tentacle
case 1: spell_id = 64983; break; // Summon Vanquished Constrictor Tentacle
case 2: spell_id = 64984; break; // Summon Vanquished Corruptor Tentacle
}
m_caster->CastSpell(m_caster, spell_id, true);
return;
}
case 65206: // Destabilization Matrix
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 65346: // Proximity Mine
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(m_caster, m_caster->GetMap()->IsRegularDifficulty() ? 66351 : 63009, true);
m_caster->RemoveAurasDueToSpell(65345);
m_caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
return;
}
case 65869: // Disengage
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 65870, true);
return;
}
case 66312: // Light Ball Passive
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_UNIT)
return;
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
if (unitTarget->HasAuraOfDifficulty(65686))
unitTarget->CastSpell(unitTarget, 67590, true);
else
m_caster->CastSpell(m_caster, 65795, true);
((Creature*)m_caster)->ForcedDespawn();
}
return;
}
case 66314: // Dark Ball Passive
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_UNIT)
return;
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
if (unitTarget->HasAuraOfDifficulty(65684))
unitTarget->CastSpell(unitTarget, 67590, true);
else
m_caster->CastSpell(m_caster, 65808, true);
((Creature*)m_caster)->ForcedDespawn();
}
return;
}
case 66390: // Read Last Rites
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Summon Tualiq Proxy
// Not known what purpose this has
unitTarget->CastSpell(unitTarget, 66411, true);
// Summon Tualiq Spirit
// Offtopic note: the summoned has aura from spell 37119 and 66419. One of them should
// most likely make summoned "rise", hover up/sideways in the air (MOVEFLAG_LEVITATING + MOVEFLAG_HOVER)
unitTarget->CastSpell(unitTarget, 66412, true);
((Player*)m_caster)->KilledMonsterCredit(unitTarget->GetEntry(), unitTarget->GetObjectGuid());
// Must have a delay for proper spell animation
((Creature*)unitTarget)->ForcedDespawn(1000);
return;
}
case 67019: // Flask of the North
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (m_caster->getClass())
{
case CLASS_WARRIOR:
case CLASS_DEATH_KNIGHT:
spell_id = 67018; // STR for Warriors, Death Knights
break;
case CLASS_ROGUE:
case CLASS_HUNTER:
spell_id = 67017; // AP for Rogues, Hunters
break;
case CLASS_PRIEST:
case CLASS_MAGE:
case CLASS_WARLOCK:
spell_id = 67016; // SPD for Priests, Mages, Warlocks
break;
case CLASS_SHAMAN:
// random (SPD, AP)
spell_id = roll_chance_i(50) ? 67016 : 67017;
break;
case CLASS_PALADIN:
case CLASS_DRUID:
default:
// random (SPD, STR)
spell_id = roll_chance_i(50) ? 67016 : 67018;
break;
}
m_caster->CastSpell(m_caster, spell_id, true);
return;
}
case 69922: // Temper Quel'Delar
{
if (!unitTarget)
return;
// Return Tempered Quel'Delar
unitTarget->CastSpell(m_caster, 69956, true);
return;
}
case 71307: // Vile Gas
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 71445: // Twilight Bloodbolt
case 71471: // Twilight Bloodbolt
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 71818, true);
return;
}
case 71718: // Conjure Flame
case 72040: // Conjure Empowered Flame
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 71837: // Vampiric Bite
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 71726, true);
return;
}
case 71861: // Swarming Shadows
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 71264, true);
return;
}
case 72202: // Blood Link
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 72195, true);
return;
}
case 72254: // Mark of the Fallen Champion
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 72261: // Delirious Slash
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, m_caster->CanReachWithMeleeAttack(unitTarget) ? 71623 : 72264, true);
return;
}
case 72285: // Vile Gas Trigger
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 74452: // Conflagration
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 74453, true);
m_caster->CastSpell(unitTarget, 74454, true, nullptr, nullptr, m_caster->GetObjectGuid(), m_spellInfo);
return;
}
}
break;
}
case SPELLFAMILY_MAGE:
{
switch (m_spellInfo->Id)
{
case 11958: // Cold Snap
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// immediately finishes the cooldown on Frost spells
const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->GetSpellFamilyName() == SPELLFAMILY_MAGE &&
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0)
{
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first, true);
}
else
++itr;
}
return;
}
case 31687: // Summon Water Elemental
{
if (m_caster->HasAura(70937)) // Glyph of Eternal Water (permanent limited by known spells version)
m_caster->CastSpell(m_caster, 70908, true);
else // temporary version
m_caster->CastSpell(m_caster, 70907, true);
return;
}
case 32826: // Polymorph Cast Visual
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
{
// Polymorph Cast Visual Rank 1
const uint32 spell_list[6] =
{
32813, // Squirrel Form
32816, // Giraffe Form
32817, // Serpent Form
32818, // Dragonhawk Form
32819, // Worgen Form
32820 // Sheep Form
};
unitTarget->CastSpell(unitTarget, spell_list[urand(0, 5)], true);
}
return;
}
case 38194: // Blink
{
// Blink
if (unitTarget)
m_caster->CastSpell(unitTarget, 38203, true);
return;
}
}
// Conjure Mana Gem
if (effect->EffectIndex == EFFECT_INDEX_1 && m_spellInfo->GetSpellEffectIdByIndex(EFFECT_INDEX_0) == SPELL_EFFECT_CREATE_ITEM)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// checked in create item check, avoid unexpected
if (Item* item = ((Player*)m_caster)->GetItemByLimitedCategory(ITEM_LIMIT_CATEGORY_MANA_GEM))
if (item->HasMaxCharges())
return;
unitTarget->CastSpell( unitTarget, effect->CalculateSimpleValue(), true, m_CastItem);
return;
}
break;
}
case SPELLFAMILY_WARRIOR:
{
SpellClassOptionsEntry const* warClassOptions = m_spellInfo->GetSpellClassOptions();
// Charge
if (warClassOptions && (warClassOptions->SpellFamilyFlags & UI64LIT(0x1)) && m_spellInfo->SpellVisual[0] == 867)
{
int32 chargeBasePoints0 = damage;
m_caster->CastCustomSpell(m_caster, 34846, &chargeBasePoints0, nullptr, nullptr, true);
return;
}
// Execute
if (warClassOptions && warClassOptions->SpellFamilyFlags & UI64LIT(0x20000000))
{
if (!unitTarget)
return;
uint32 rage = m_caster->GetPower(POWER_RAGE);
// up to max 30 rage cost
if (rage > 300)
rage = 300;
// Glyph of Execution bonus
uint32 rage_modified = rage;
if (Aura* aura = m_caster->GetDummyAura(58367))
rage_modified += aura->GetModifier()->m_amount * 10;
int32 basePoints0 = damage+int32(rage_modified * effect->EffectDamageMultiplier +
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, nullptr, nullptr, true, 0);
// Sudden Death
if (m_caster->HasAura(52437))
{
Unit::AuraList const& auras = m_caster->GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
for (Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
// Only Sudden Death have this SpellIconID with SPELL_AURA_PROC_TRIGGER_SPELL
if ((*itr)->GetSpellProto()->SpellIconID == 1989)
{
// saved rage top stored in next affect
uint32 lastrage = (*itr)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_1) * 10;
if (lastrage < rage)
rage -= lastrage;
break;
}
}
}
m_caster->SetPower(POWER_RAGE, m_caster->GetPower(POWER_RAGE) - rage);
return;
}
// Slam
if (warClassOptions && warClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000200000))
{
if (!unitTarget)
return;
// dummy cast itself ignored by client in logs
m_caster->CastCustomSpell(unitTarget, 50782, &damage, nullptr, nullptr, true);
return;
}
// Concussion Blow
if (warClassOptions && warClassOptions->SpellFamilyFlags & UI64LIT(0x0000000004000000))
{
m_damage += uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
return;
}
switch (m_spellInfo->Id)
{
// Warrior's Wrath
case 21977:
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 21887, true); // spell mod
return;
}
// Last Stand
case 12975:
{
int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth() * 0.3);
m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, nullptr, nullptr, true, nullptr);
return;
}
// Bloodthirst
case 23881:
{
m_caster->CastCustomSpell(unitTarget, 23885, &damage, nullptr, nullptr, true, nullptr);
return;
}
case 30012: // Move
{
if (!unitTarget || unitTarget->HasAura(39400))
return;
unitTarget->CastSpell(m_caster, 30253, true);
}
case 30284: // Change Facing
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 30270, true);
return;
}
case 37144: // Move (Chess event player knight move)
case 37146: // Move (Chess event player pawn move)
case 37148: // Move (Chess event player queen move)
case 37151: // Move (Chess event player rook move)
case 37152: // Move (Chess event player bishop move)
case 37153: // Move (Chess event player king move)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// cast generic move spell
m_caster->CastSpell(unitTarget, 30012, true);
return;
}
}
break;
}
case SPELLFAMILY_WARLOCK:
{
SpellClassOptionsEntry const* wrlClassOptions = m_spellInfo->GetSpellClassOptions();
// Life Tap
if (wrlClassOptions && wrlClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000040000))
{
if (unitTarget && (int32(unitTarget->GetHealth()) > damage))
{
// Shouldn't Appear in Combat Log
unitTarget->ModifyHealth(-damage);
int32 spell_power = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
int32 mana = damage + spell_power / 2;
// Improved Life Tap mod
Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
if((*itr)->GetSpellProto()->GetSpellFamilyName()==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
m_caster->CastCustomSpell(unitTarget, 31818, &mana, nullptr, nullptr, true);
// Mana Feed
int32 manaFeedVal = 0;
Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
for (Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
{
if((*itr)->GetSpellProto()->GetSpellFamilyName()==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
manaFeedVal+= (*itr)->GetModifier()->m_amount;
}
if (manaFeedVal > 0)
{
manaFeedVal = manaFeedVal * mana / 100;
m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, nullptr, nullptr, true, nullptr);
}
}
else
SendCastResult(SPELL_FAILED_FIZZLE);
return;
}
break;
}
case SPELLFAMILY_PRIEST:
{
SpellClassOptionsEntry const* prtsClassOptions = m_spellInfo->GetSpellClassOptions();
// Penance
if (prtsClassOptions && prtsClassOptions->SpellFamilyFlags & UI64LIT(0x0080000000000000))
{
if (!unitTarget)
return;
int hurt = 0;
int heal = 0;
switch (m_spellInfo->Id)
{
case 47540: hurt = 47758; heal = 47757; break;
case 53005: hurt = 53001; heal = 52986; break;
case 53006: hurt = 53002; heal = 52987; break;
case 53007: hurt = 53003; heal = 52988; break;
default:
sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
return;
}
// prevent interrupted message for main spell
finish(true);
// replace cast by selected spell, this also make it interruptible including target death case
if (m_caster->IsFriendlyTo(unitTarget))
m_caster->CastSpell(unitTarget, heal, false);
else
m_caster->CastSpell(unitTarget, hurt, false);
return;
}
break;
}
case SPELLFAMILY_DRUID:
{
// Starfall
if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00000100))
{
// Shapeshifting into an animal form or mounting cancels the effect.
if (m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
{
if (m_triggeredByAuraSpell)
m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
return;
}
// Any effect which causes you to lose control of your character will supress the starfall effect.
if (m_caster->hasUnitState(UNIT_STAT_NO_FREE_MOVE))
return;
switch (m_spellInfo->Id)
{
case 50286: m_caster->CastSpell(unitTarget, 50288, true); return;
case 53196: m_caster->CastSpell(unitTarget, 53191, true); return;
case 53197: m_caster->CastSpell(unitTarget, 53194, true); return;
case 53198: m_caster->CastSpell(unitTarget, 53195, true); return;
default:
sLog.outError("Spell::EffectDummy: Unhandeled Starfall spell rank %u", m_spellInfo->Id);
return;
}
}
break;
}
case SPELLFAMILY_ROGUE:
{
switch (m_spellInfo->Id)
{
case 5938: // Shiv
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* pCaster = ((Player*)m_caster);
Item* item = pCaster->GetWeaponForAttack(OFF_ATTACK);
if (!item)
return;
// all poison enchantments is temporary
uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
if (!enchant_id)
return;
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if (!pEnchant)
return;
for (int s = 0; s < 3; ++s)
{
if (pEnchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
continue;
SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
if (!combatEntry || combatEntry->GetDispel() != DISPEL_POISON)
continue;
m_caster->CastSpell(unitTarget, combatEntry, true, item);
}
m_caster->CastSpell(unitTarget, 5940, true);
return;
}
case 14185: // Preparation
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// immediately finishes the cooldown on certain Rogue abilities
const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
SpellClassOptionsEntry const* prepClassOptions = spellInfo->GetSpellClassOptions();
if (prepClassOptions && prepClassOptions->SpellFamilyName == SPELLFAMILY_ROGUE && (prepClassOptions->SpellFamilyFlags & UI64LIT(0x0000024000000860)))
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
else
++itr;
}
return;
}
case 31231: // Cheat Death
{
// Cheating Death
m_caster->CastSpell(m_caster, 45182, true);
return;
}
case 51662: // Hunger for Blood
{
m_caster->CastSpell(m_caster, 63848, true);
return;
}
}
break;
}
case SPELLFAMILY_HUNTER:
{
SpellClassOptionsEntry const* huntClassOptions = m_spellInfo->GetSpellClassOptions();
// Steady Shot
if (huntClassOptions && huntClassOptions->SpellFamilyFlags & UI64LIT(0x100000000))
{
if (!unitTarget || !unitTarget->IsAlive())
return;
bool found = false;
// check dazed affect
Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
for (Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
{
if ((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->GetDispel()==0)
{
found = true;
break;
}
}
if (found)
m_damage += damage;
return;
}
// Disengage
if (huntClassOptions && huntClassOptions->SpellFamilyFlags & UI64LIT(0x0000400000000000))
{
Unit* target = unitTarget;
uint32 spellid;
switch (m_spellInfo->Id)
{
case 57635: spellid = 57636; break; // one from creature cases
case 61507: spellid = 61508; break; // one from creature cases
default:
sLog.outError("Spell %u not handled propertly in EffectDummy(Disengage)", m_spellInfo->Id);
return;
}
if (!target || !target->IsAlive())
return;
m_caster->CastSpell(target, spellid, true, nullptr);
}
switch (m_spellInfo->Id)
{
case 23989: // Readiness talent
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// immediately finishes the cooldown for hunter abilities
const SpellCooldowns& cm = ((Player*)m_caster)->GetSpellCooldownMap();
for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo->GetSpellFamilyName() == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true);
else
++itr;
}
return;
}
case 37506: // Scatter Shot
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// break Auto Shot and autohit
m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
m_caster->AttackStop();
((Player*)m_caster)->SendAttackSwingCancelAttack();
return;
}
// Last Stand
case 53478:
{
if (!unitTarget)
return;
int32 healthModSpellBasePoints0 = int32(unitTarget->GetMaxHealth() * 0.3);
unitTarget->CastCustomSpell(unitTarget, 53479, &healthModSpellBasePoints0, nullptr, nullptr, true, nullptr);
return;
}
// Master's Call
case 53271:
{
Pet* pet = m_caster->GetPet();
if (!pet || !unitTarget)
return;
pet->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
}
break;
}
case SPELLFAMILY_PALADIN:
{
switch (m_spellInfo->SpellIconID)
{
case 156: // Holy Shock
{
if (!unitTarget)
return;
int hurt = 0;
int heal = 0;
switch (m_spellInfo->Id)
{
case 20473: hurt = 25912; heal = 25914; break;
case 20929: hurt = 25911; heal = 25913; break;
case 20930: hurt = 25902; heal = 25903; break;
case 27174: hurt = 27176; heal = 27175; break;
case 33072: hurt = 33073; heal = 33074; break;
case 48824: hurt = 48822; heal = 48820; break;
case 48825: hurt = 48823; heal = 48821; break;
default:
sLog.outError("Spell::EffectDummy: Spell %u not handled in HS", m_spellInfo->Id);
return;
}
if (m_caster->IsFriendlyTo(unitTarget))
m_caster->CastSpell(unitTarget, heal, true);
else
m_caster->CastSpell(unitTarget, hurt, true);
return;
}
case 561: // Judgement of command
{
if (!unitTarget)
return;
uint32 spell_id = m_currentBasePoints[effect->EffectIndex];
SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
if (!spell_proto)
return;
m_caster->CastSpell(unitTarget, spell_proto, true, nullptr);
return;
}
}
switch (m_spellInfo->Id)
{
case 31789: // Righteous Defense (step 1)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
{
SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
return;
}
// 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
Unit* friendTarget = !unitTarget || unitTarget->IsFriendlyTo(m_caster) ? unitTarget : unitTarget->getVictim();
if (friendTarget)
{
Player* player = friendTarget->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!player || !player->IsInSameRaidWith((Player*)m_caster))
friendTarget = nullptr;
}
// non-standard cast requirement check
if (!friendTarget || friendTarget->getAttackers().empty())
{
((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id, true);
SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
return;
}
// Righteous Defense (step 2) (in old version 31980 dummy effect)
// Clear targets for eff 1
for (TargetList::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
ihit->effectMask &= ~(1 << 1);
// not empty (checked), copy
Unit::AttackerSet attackers = friendTarget->getAttackers();
// selected from list 3
for (uint32 i = 0; i < std::min(size_t(3), attackers.size()); ++i)
{
Unit::AttackerSet::iterator aItr = attackers.begin();
std::advance(aItr, rand() % attackers.size());
AddUnitTarget((*aItr), EFFECT_INDEX_1);
attackers.erase(aItr);
}
// now let next effect cast spell at each target.
return;
}
case 37877: // Blessing of Faith
{
if (!unitTarget)
return;
uint32 spell_id = 0;
switch (unitTarget->getClass())
{
case CLASS_DRUID: spell_id = 37878; break;
case CLASS_PALADIN: spell_id = 37879; break;
case CLASS_PRIEST: spell_id = 37880; break;
case CLASS_SHAMAN: spell_id = 37881; break;
default: return; // ignore for not healing classes
}
m_caster->CastSpell(m_caster, spell_id, true);
return;
}
}
break;
}
case SPELLFAMILY_SHAMAN:
{
SpellClassOptionsEntry const* shamClassOptions = m_spellInfo->GetSpellClassOptions();
// Cleansing Totem
if (shamClassOptions && (shamClassOptions->SpellFamilyFlags & UI64LIT(0x0000000004000000)) && m_spellInfo->SpellIconID==1673)
{
if (unitTarget)
m_caster->CastSpell(unitTarget, 52025, true);
return;
}
// Healing Stream Totem
if (shamClassOptions && shamClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000002000))
{
if (unitTarget)
{
if (Unit* owner = m_caster->GetOwner())
{
// spell have SPELL_DAMAGE_CLASS_NONE and not get bonuses from owner, use main spell for bonuses
if (m_triggeredBySpellInfo)
{
damage = int32(owner->SpellHealingBonusDone(unitTarget, m_triggeredBySpellInfo, damage, HEAL));
damage = int32(unitTarget->SpellHealingBonusTaken(owner, m_triggeredBySpellInfo, damage, HEAL));
}
// Restorative Totems
Unit::AuraList const& mDummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
// only its have dummy with specific icon
if ((*i)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_SHAMAN && (*i)->GetSpellProto()->SpellIconID == 338)
damage += (*i)->GetModifier()->m_amount * damage / 100;
// Glyph of Healing Stream Totem
if (Aura* dummy = owner->GetDummyAura(55456))
damage += dummy->GetModifier()->m_amount * damage / 100;
}
m_caster->CastCustomSpell(unitTarget, 52042, &damage, nullptr, nullptr, true, 0, 0, m_originalCasterGUID);
}
return;
}
// Mana Spring Totem
if (shamClassOptions && shamClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000004000))
{
if (!unitTarget || unitTarget->GetPowerType() != POWER_MANA)
return;
m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
return;
}
// Flametongue Weapon Proc, Ranks
if (shamClassOptions && shamClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000200000))
{
if (!m_CastItem)
{
sLog.outError("Spell::EffectDummy: spell %i requires cast Item", m_spellInfo->Id);
return;
}
// found spelldamage coefficients of 0.381% per 0.1 speed and 15.244 per 4.0 speed
// but own calculation say 0.385 gives at most one point difference to published values
int32 spellDamage = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
float weaponSpeed = (1.0f / IN_MILLISECONDS) * m_CastItem->GetProto()->Delay;
int32 totalDamage = int32((damage + 3.85f * spellDamage) * 0.01 * weaponSpeed);
m_caster->CastCustomSpell(unitTarget, 10444, &totalDamage, nullptr, nullptr, true, m_CastItem);
return;
}
if (m_spellInfo->Id == 39610) // Mana Tide Totem effect
{
if (!unitTarget || unitTarget->GetPowerType() != POWER_MANA)
return;
// Glyph of Mana Tide
if (Unit* owner = m_caster->GetOwner())
if (Aura* dummy = owner->GetDummyAura(55441))
damage += dummy->GetModifier()->m_amount;
// Regenerate 6% of Total Mana Every 3 secs
int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
m_caster->CastCustomSpell(unitTarget, 39609, &EffectBasePoints0, nullptr, nullptr, true, nullptr, nullptr, m_originalCasterGUID);
return;
}
// Lava Lash
if (m_spellInfo->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00000004))
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Item* item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (item)
{
// Damage is increased if your off-hand weapon is enchanted with Flametongue.
Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
{
if ((*itr)->GetSpellProto()->IsFitToFamily(SPELLFAMILY_SHAMAN, UI64LIT(0x0000000000200000)) &&
(*itr)->GetCastItemGuid() == item->GetObjectGuid())
{
m_damage += m_damage * damage / 100;
return;
}
}
}
return;
}
// Fire Nova
if (m_spellInfo->SpellIconID == 33)
{
// fire totems slot
Totem* totem = m_caster->GetTotem(TOTEM_SLOT_FIRE);
if (!totem)
return;
uint32 triggered_spell_id;
switch (m_spellInfo->Id)
{
case 1535: triggered_spell_id = 8349; break;
case 8498: triggered_spell_id = 8502; break;
case 8499: triggered_spell_id = 8503; break;
case 11314: triggered_spell_id = 11306; break;
case 11315: triggered_spell_id = 11307; break;
case 25546: triggered_spell_id = 25535; break;
case 25547: triggered_spell_id = 25537; break;
case 61649: triggered_spell_id = 61650; break;
case 61657: triggered_spell_id = 61654; break;
default: return;
}
totem->CastSpell(totem, triggered_spell_id, true, nullptr, nullptr, m_caster->GetObjectGuid());
// Fire Nova Visual
totem->CastSpell(totem, 19823, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
SpellClassOptionsEntry const* dkClassOptions = m_spellInfo->GetSpellClassOptions();
// Death Coil
if (dkClassOptions && dkClassOptions->SpellFamilyFlags & UI64LIT(0x002000))
{
if (m_caster->IsFriendlyTo(unitTarget))
{
if (!unitTarget || unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
return;
int32 bp = int32(damage * 1.5f);
m_caster->CastCustomSpell(unitTarget, 47633, &bp, nullptr, nullptr, true);
}
else
{
int32 bp = damage;
m_caster->CastCustomSpell(unitTarget, 47632, &bp, nullptr, nullptr, true);
}
return;
}
// Hungering Cold
else if (dkClassOptions && dkClassOptions->SpellFamilyFlags & UI64LIT(0x0000100000000000))
{
m_caster->CastSpell(m_caster, 51209, true);
return;
}
// Death Strike
else if (dkClassOptions && dkClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000010))
{
uint32 count = 0;
Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if (itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE &&
itr->second->GetCasterGuid() == m_caster->GetObjectGuid())
{
++count;
// max. 15%
if (count == 3)
break;
}
}
SpellEffectEntry const* dsSpellEffect = m_spellInfo->GetSpellEffect(EFFECT_INDEX_0);
int32 bp = int32(count * m_caster->GetMaxHealth() * (dsSpellEffect ? dsSpellEffect->EffectDamageMultiplier : 0.0f) / 100);
// Improved Death Strike (percent stored in nonexistent EFFECT_INDEX_2 effect base points)
Unit::AuraList const& auraMod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
for (Unit::AuraList::const_iterator iter = auraMod.begin(); iter != auraMod.end(); ++iter)
{
// only required spell have spellicon for SPELL_AURA_ADD_FLAT_MODIFIER
if ((*iter)->GetSpellProto()->SpellIconID == 2751 && (*iter)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DEATHKNIGHT)
{
bp += (*iter)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2) * bp / 100;
break;
}
}
m_caster->CastCustomSpell(m_caster, 45470, &bp, nullptr, nullptr, true);
return;
}
// Death Grip
else if (m_spellInfo->Id == 49576)
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 49560, true);
return;
}
// Death Grip
else if (m_spellInfo->Id == 49560)
{
if (!unitTarget || unitTarget == m_caster)
return;
uint32 spellId = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_0);
float dest_x, dest_y;
m_caster->GetNearPoint2D(dest_x, dest_y, m_caster->GetObjectBoundingRadius() + unitTarget->GetObjectBoundingRadius(), m_caster->GetOrientation());
unitTarget->CastSpell(dest_x, dest_y, m_caster->GetPositionZ() + 0.5f, spellId, true, nullptr, nullptr, m_caster->GetObjectGuid(), m_spellInfo);
return;
}
// Obliterate
else if (dkClassOptions && dkClassOptions->SpellFamilyFlags & UI64LIT(0x0002000000000000))
{
// search for Annihilation
Unit::AuraList const& dummyList = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator itr = dummyList.begin(); itr != dummyList.end(); ++itr)
{
if ((*itr)->GetSpellProto()->GetSpellFamilyName() == SPELLFAMILY_DEATHKNIGHT && (*itr)->GetSpellProto()->SpellIconID == 2710)
{
if (roll_chance_i((*itr)->GetModifier()->m_amount)) // don't consume if found
return;
else
break;
}
}
// consume diseases
unitTarget->RemoveAurasWithDispelType(DISPEL_DISEASE, m_caster->GetObjectGuid());
}
break;
}
}
// pet auras
if (PetAura const* petSpell = sSpellMgr.GetPetAura(m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex)))
{
m_caster->AddPetAura(petSpell);
return;
}
// Script based implementation. Must be used only for not good for implementation in core spell effects
// So called only for not processed cases
bool libraryResult = false;
if (gameObjTarget)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), gameObjTarget, m_originalCasterGUID);
else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget, m_originalCasterGUID);
else if (itemTarget)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), itemTarget, m_originalCasterGUID);
if (libraryResult || !unitTarget)
return;
// Previous effect might have started script
if (!ScriptMgr::CanSpellEffectStartDBScript(m_spellInfo, SpellEffectIndex(effect->EffectIndex)))
return;
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart spellid %u in EffectDummy", m_spellInfo->Id);
m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
void Spell::EffectTriggerSpellWithValue(SpellEffectEntry const* effect)
{
uint32 triggered_spell_id = effect->EffectTriggerSpell;
// normal case
SpellEntry const* spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
if (!spellInfo)
{
sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
return;
}
int32 bp = damage;
m_caster->CastCustomSpell(unitTarget, triggered_spell_id, &bp, &bp, &bp, true, m_CastItem , nullptr, m_originalCasterGUID, m_spellInfo);
}
void Spell::EffectTriggerRitualOfSummoning(SpellEffectEntry const* effect)
{
uint32 triggered_spell_id = effect->EffectTriggerSpell;
SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
if (!spellInfo)
{
sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
return;
}
finish();
m_caster->CastSpell(unitTarget, spellInfo, false);
}
void Spell::EffectClearQuest(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)m_caster;
uint32 quest_id = effect->EffectMiscValue;
if (!sObjectMgr.GetQuestTemplate(quest_id))
{
sLog.outError("Spell::EffectClearQuest spell entry %u attempt clear quest entry %u but this quest does not exist.", m_spellInfo->Id, quest_id);
return;
}
// remove quest possibly in quest log (is that expected?)
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 quest = player->GetQuestSlotQuestId(slot);
if (quest == quest_id)
{
player->SetQuestSlot(slot, 0);
// ignore unequippable quest items in this case, it will still be equipped
player->TakeQuestSourceItem(quest_id, false);
}
}
player->SetQuestStatus(quest_id, QUEST_STATUS_NONE);
player->getQuestStatusMap()[quest_id].m_rewarded = false;
}
void Spell::EffectForceCast(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
uint32 triggered_spell_id = effect->EffectTriggerSpell;
// normal case
SpellEntry const* spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
if (!spellInfo)
{
sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
return;
}
int32 basePoints = damage;
// forced cast spells by vehicle on master always unboard the master
if (m_caster->IsVehicle() && m_caster->GetVehicleInfo()->HasOnBoard(unitTarget) &&
effect->EffectImplicitTargetA == TARGET_MASTER)
{
if (sSpellStore.LookupEntry(basePoints))
m_caster->RemoveAurasDueToSpell(basePoints);
}
// spell effect 141 needs to be cast as custom with basePoints
if (effect->Effect == SPELL_EFFECT_FORCE_CAST_WITH_VALUE)
unitTarget->CastCustomSpell(unitTarget, spellInfo, &basePoints, &basePoints, &basePoints, true, nullptr , nullptr, m_originalCasterGUID, m_spellInfo);
else
unitTarget->CastSpell(unitTarget, spellInfo, true, nullptr, nullptr, m_originalCasterGUID, m_spellInfo);
}
void Spell::EffectTriggerSpell(SpellEffectEntry const* effect)
{
// only unit case known
if (!unitTarget)
{
if (gameObjTarget || itemTarget)
sLog.outError("Spell::EffectTriggerSpell (Spell: %u): Unsupported non-unit case!", m_spellInfo->Id);
return;
}
uint32 triggered_spell_id = effect->EffectTriggerSpell;
// special cases
switch (triggered_spell_id)
{
case 18461: // Vanish (not exist)
{
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
// if this spell is given to NPC it must handle rest by it's own AI
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spellId = 1784;
// reset cooldown on it if needed
if (((Player*)unitTarget)->HasSpellCooldown(spellId))
((Player*)unitTarget)->RemoveSpellCooldown(spellId);
m_caster->CastSpell(unitTarget, spellId, true);
return;
}
case 29284: // Brittle Armor - (need add max stack of 24575 Brittle Armor)
m_caster->CastSpell(unitTarget, 24575, true, m_CastItem, NULL, m_originalCasterGUID);
return;
case 29286: // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
m_caster->CastSpell(unitTarget, 26464, true, m_CastItem, NULL, m_originalCasterGUID);
return;
case 31980: // Righteous Defense
{
m_caster->CastSpell(unitTarget, 31790, true, m_CastItem, NULL, m_originalCasterGUID);
return;
}
case 35729: // Cloak of Shadows
{
Unit::SpellAuraHolderMap& Auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
{
// Remove all harmful spells on you except positive/passive/physical auras
if (!iter->second->IsPositive() &&
!iter->second->IsPassive() &&
!iter->second->IsDeathPersistent() &&
(GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL) == 0)
{
m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
iter = Auras.begin();
}
}
return;
}
case 41967: // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
{
if (Unit* pet = unitTarget->GetPet())
pet->CastSpell(pet, 28305, true);
return;
}
case 58832: // Mirror Image
{
// Glyph of Mirror Image
if (m_caster->HasAura(63093))
m_caster->CastSpell(m_caster, 65047, true, m_CastItem, nullptr, m_originalCasterGUID);
break;
}
}
// normal case
SpellEntry const* spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
if (!spellInfo)
{
// No previous Effect might have started a script
bool startDBScript = unitTarget && ScriptMgr::CanSpellEffectStartDBScript(m_spellInfo, SpellEffectIndex(effect->EffectIndex));
if (startDBScript)
{
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart spellid %u in EffectTriggerSpell", m_spellInfo->Id);
startDBScript = m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
if (!startDBScript)
sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
return;
}
// select formal caster for triggered spell
Unit* caster = m_caster;
// some triggered spells require specific equipment
if (spellInfo->GetEquippedItemClass() >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
{
// main hand weapon required
if (spellInfo->HasAttribute(SPELL_ATTR_EX3_MAIN_HAND))
{
Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK, true, false);
// skip spell if no weapon in slot or broken
if (!item)
return;
// skip spell if weapon not fit to triggered spell
if (!item->IsFitToSpellRequirements(spellInfo))
return;
}
// offhand hand weapon required
if (spellInfo->HasAttribute(SPELL_ATTR_EX3_REQ_OFFHAND))
{
Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK, true, false);
// skip spell if no weapon in slot or broken
if (!item)
return;
// skip spell if weapon not fit to triggered spell
if (!item->IsFitToSpellRequirements(spellInfo))
return;
}
}
else
{
// Note: not exist spells with weapon req. and IsSpellHaveCasterSourceTargets == true
// so this just for speedup places in else
caster = IsSpellWithCasterSourceTargetsOnly(spellInfo) ? unitTarget : m_caster;
}
caster->CastSpell(unitTarget, spellInfo, true, m_CastItem, NULL, m_originalCasterGUID, m_spellInfo);
}
void Spell::EffectTriggerMissileSpell(SpellEffectEntry const* effect)
{
uint32 triggered_spell_id = effect->EffectTriggerSpell;
// normal case
SpellEntry const* spellInfo = sSpellStore.LookupEntry(triggered_spell_id);
if (!spellInfo)
{
if (unitTarget)
{
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart spellid %u in EffectTriggerMissileSpell", m_spellInfo->Id);
m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
else
sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
m_spellInfo->Id, effect->EffectIndex, triggered_spell_id);
return;
}
if (m_CastItem)
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "WORLD: cast Item spellId - %i", spellInfo->Id);
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, nullptr, m_originalCasterGUID, m_spellInfo);
else if (unitTarget)
m_caster->CastSpell(unitTarget, spellInfo, true, m_CastItem, nullptr, m_originalCasterGUID, m_spellInfo);
}
void Spell::EffectJump(SpellEffectEntry const* effect)
{
if (m_caster->IsTaxiFlying())
return;
// Init dest coordinates
float x, y, z, o;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
{
m_targets.getDestination(x, y, z);
if(effect->EffectImplicitTargetA == TARGET_BEHIND_VICTIM)
{
// explicit cast data from client or server-side cast
// some spell at client send caster
Unit* pTarget = NULL;
if (m_targets.getUnitTarget() && m_targets.getUnitTarget() != m_caster)
pTarget = m_targets.getUnitTarget();
else if (unitTarget->getVictim())
pTarget = m_caster->getVictim();
else if (m_caster->GetTypeId() == TYPEID_PLAYER)
pTarget = m_caster->GetMap()->GetUnit(((Player*)m_caster)->GetSelectionGuid());
o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
}
else
o = m_caster->GetOrientation();
}
else if (unitTarget)
{
unitTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE);
o = m_caster->GetOrientation();
}
else if (gameObjTarget)
{
gameObjTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE);
o = m_caster->GetOrientation();
}
else
{
sLog.outError("Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id);
return;
}
// Try to normalize Z coord because GetContactPoint do nothing with Z axis
m_caster->UpdateAllowedPositionZ(x, y, z);
float speed = m_spellInfo->speed ? m_spellInfo->speed : 27.0f;
m_caster->GetMotionMaster()->MoveDestination(x, y, z, o, speed, 2.5f);
}
void Spell::EffectTeleportUnits(SpellEffectEntry const* effect) // TODO - Use target settings for this effect!
{
if (!unitTarget || unitTarget->IsTaxiFlying())
return;
switch (m_spellInfo->Id)
{
case 48129: // Scroll of Recall
case 60320: // Scroll of Recall II
case 60321: // Scroll of Recall III
{
uint32 failAtLevel = 0;
switch (m_spellInfo->Id)
{
case 48129: failAtLevel = 40; break;
case 60320: failAtLevel = 70; break;
case 60321: failAtLevel = 80; break;
}
if (unitTarget->getLevel() > failAtLevel && unitTarget->GetTypeId() == TYPEID_PLAYER)
{
unitTarget->CastSpell(unitTarget, 60444, true);
// TODO: Unclear use of probably related spell 60322
uint32 spellId = (((Player*)unitTarget)->GetTeam() == ALLIANCE ? 60323 : 60328) + urand(0, 7);
unitTarget->CastSpell(unitTarget, spellId, true);
return;
}
break;
}
}
// Target dependend on TargetB, if there is none provided, decide dependend on A
uint32 targetType = effect->EffectImplicitTargetB;
if (!targetType)
targetType = effect->EffectImplicitTargetA;
switch (targetType)
{
case TARGET_INNKEEPER_COORDINATES:
{
// Only players can teleport to innkeeper
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->TeleportToHomebind(unitTarget == m_caster ? TELE_TO_SPELL : 0);
return;
}
case TARGET_AREAEFFECT_INSTANT: // in all cases first TARGET_TABLE_X_Y_Z_COORDINATES
case TARGET_TABLE_X_Y_Z_COORDINATES:
{
SpellTargetPosition const* st = sSpellMgr.GetSpellTargetPosition(m_spellInfo->Id);
if (!st)
{
sLog.outError("Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id);
return;
}
if (st->target_mapId == unitTarget->GetMapId())
unitTarget->NearTeleportTo(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, unitTarget == m_caster);
else if (unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->TeleportTo(st->target_mapId, st->target_X, st->target_Y, st->target_Z, st->target_Orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0);
break;
}
case TARGET_EFFECT_SELECT:
{
// m_destN filled, but sometimes for wrong dest and does not have TARGET_FLAG_DEST_LOCATION
float x = unitTarget->GetPositionX();
float y = unitTarget->GetPositionY();
float z = unitTarget->GetPositionZ();
float orientation = m_caster->GetOrientation();
m_caster->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
return;
}
case TARGET_BEHIND_VICTIM:
{
Unit* pTarget = NULL;
// explicit cast data from client or server-side cast
// some spell at client send caster
if (m_targets.getUnitTarget() && m_targets.getUnitTarget() != unitTarget)
pTarget = m_targets.getUnitTarget();
else if (unitTarget->getVictim())
pTarget = unitTarget->getVictim();
else if (unitTarget->GetTypeId() == TYPEID_PLAYER)
pTarget = unitTarget->GetMap()->GetUnit(((Player*)unitTarget)->GetSelectionGuid());
// Init dest coordinates
float x = m_targets.m_destX;
float y = m_targets.m_destY;
float z = m_targets.m_destZ;
float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation();
unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
return;
}
default:
{
// If not exist data for dest location - return
if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
{
sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u", effect->EffectIndex, effect->EffectImplicitTargetB, m_spellInfo->Id );
return;
}
// Init dest coordinates
float x = m_targets.m_destX;
float y = m_targets.m_destY;
float z = m_targets.m_destZ;
float orientation = unitTarget->GetOrientation();
// Teleport
unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
return;
}
}
// post effects for TARGET_TABLE_X_Y_Z_COORDINATES
switch (m_spellInfo->Id)
{
// Dimensional Ripper - Everlook
case 23442:
{
int32 r = irand(0, 119);
if (r >= 70) // 7/12 success
{
if (r < 100) // 4/12 evil twin
m_caster->CastSpell(m_caster, 23445, true);
else // 1/12 fire
m_caster->CastSpell(m_caster, 23449, true);
}
return;
}
// Ultrasafe Transporter: Toshley's Station
case 36941:
{
if (roll_chance_i(50)) // 50% success
{
int32 rand_eff = urand(1, 7);
switch (rand_eff)
{
case 1:
// soul split - evil
m_caster->CastSpell(m_caster, 36900, true);
break;
case 2:
// soul split - good
m_caster->CastSpell(m_caster, 36901, true);
break;
case 3:
// Increase the size
m_caster->CastSpell(m_caster, 36895, true);
break;
case 4:
// Decrease the size
m_caster->CastSpell(m_caster, 36893, true);
break;
case 5:
// Transform
{
if (((Player*)m_caster)->GetTeam() == ALLIANCE)
m_caster->CastSpell(m_caster, 36897, true);
else
m_caster->CastSpell(m_caster, 36899, true);
break;
}
case 6:
// chicken
m_caster->CastSpell(m_caster, 36940, true);
break;
case 7:
// evil twin
m_caster->CastSpell(m_caster, 23445, true);
break;
}
}
return;
}
// Dimensional Ripper - Area 52
case 36890:
{
if (roll_chance_i(50)) // 50% success
{
int32 rand_eff = urand(1, 4);
switch (rand_eff)
{
case 1:
// soul split - evil
m_caster->CastSpell(m_caster, 36900, true);
break;
case 2:
// soul split - good
m_caster->CastSpell(m_caster, 36901, true);
break;
case 3:
// Increase the size
m_caster->CastSpell(m_caster, 36895, true);
break;
case 4:
// Transform
{
if (((Player*)m_caster)->GetTeam() == ALLIANCE)
m_caster->CastSpell(m_caster, 36897, true);
else
m_caster->CastSpell(m_caster, 36899, true);
break;
}
}
}
return;
}
}
}
void Spell::EffectApplyAura(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
// ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
if ((!unitTarget->IsAlive() && !(IsDeathOnlySpell(m_spellInfo) || IsDeathPersistentSpell(m_spellInfo))) &&
(unitTarget->GetTypeId() != TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()))
return;
Unit* caster = GetAffectiveCaster();
if (!caster)
{
// FIXME: currently we can't have auras applied explicitly by gameobjects
// so for auras from wild gameobjects (no owner) target used
if (m_originalCasterGUID.IsGameObject())
caster = unitTarget;
else
return;
}
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell: Aura is: %u", effect->EffectApplyAuraName);
Aura* aur = CreateAura(m_spellInfo, SpellEffectIndex(effect->EffectIndex), &m_currentBasePoints[effect->EffectIndex], m_spellAuraHolder, unitTarget, caster, m_CastItem);
m_spellAuraHolder->AddAura(aur, SpellEffectIndex(effect->EffectIndex));
}
void Spell::EffectUnlearnSpecialization(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player *_player = (Player*)unitTarget;
uint32 spellToUnlearn = effect->EffectTriggerSpell;
_player->removeSpell(spellToUnlearn);
if (WorldObject const* caster = GetCastingObject())
DEBUG_LOG("Spell: %s has unlearned spell %u at %s", _player->GetGuidStr().c_str(), spellToUnlearn, caster->GetGuidStr().c_str());
}
void Spell::EffectPowerDrain(SpellEffectEntry const* effect)
{
if(effect->EffectMiscValue < 0 || effect->EffectMiscValue >= MAX_POWERS)
return;
Powers drain_power = Powers(effect->EffectMiscValue);
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
if (unitTarget->GetPowerType() != drain_power)
return;
if (damage < 0)
return;
uint32 curPower = unitTarget->GetPower(drain_power);
// add spell damage bonus
damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
uint32 power = damage;
if (drain_power == POWER_MANA)
power -= unitTarget->GetCritDamageReduction(power);
int32 new_damage;
if (curPower < power)
new_damage = curPower;
else
new_damage = power;
unitTarget->ModifyPower(drain_power, -new_damage);
// Don`t restore from self drain
if (drain_power == POWER_MANA && m_caster != unitTarget)
{
float manaMultiplier = effect->EffectMultipleValue;
if(manaMultiplier==0)
manaMultiplier = 1;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
int32 gain = int32(new_damage * manaMultiplier);
m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, POWER_MANA);
}
}
void Spell::EffectSendEvent(SpellEffectEntry const* effect)
{
/*
we do not handle a flag dropping or clicking on flag in battleground by sendevent system
TODO: Actually, why not...
*/
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart %u for spellid %u in EffectSendEvent ", effect->EffectMiscValue, m_spellInfo->Id);
StartEvents_Event(m_caster->GetMap(), effect->EffectMiscValue, m_caster, focusObject, true, m_caster);
}
void Spell::EffectPowerBurn(SpellEffectEntry const* effect)
{
if (effect->EffectMiscValue < 0 || effect->EffectMiscValue >= MAX_POWERS)
return;
Powers powertype = Powers(effect->EffectMiscValue);
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
if (unitTarget->GetPowerType() != powertype)
return;
if (damage < 0)
return;
// burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
if (m_spellInfo->GetManaCostPercentage())
{
int32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
damage = unitTarget->GetMaxPower(powertype) * damage / 100;
if (damage > maxdamage)
damage = maxdamage;
}
int32 curPower = int32(unitTarget->GetPower(powertype));
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
int32 power = damage;
if (powertype == POWER_MANA)
power -= unitTarget->GetCritDamageReduction(power);
int32 new_damage = (curPower < power) ? curPower : power;
unitTarget->ModifyPower(powertype, -new_damage);
float multiplier = effect->EffectMultipleValue;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
new_damage = int32(new_damage * multiplier);
m_damage += new_damage;
}
void Spell::EffectHeal(SpellEffectEntry const* /*effect*/)
{
if (unitTarget && unitTarget->IsAlive() && damage >= 0)
{
// Try to get original caster
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
int32 addhealth = damage;
// Seal of Light proc
if (m_spellInfo->Id == 20167)
{
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseHealingBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
addhealth += int32(ap * 0.15) + int32(holy * 15 / 100);
}
// Vessel of the Naaru (Vial of the Sunwell trinket)
else if (m_spellInfo->Id == 45064)
{
// Amount of heal - depends from stacked Holy Energy
int damageAmount = 0;
Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
if ((*i)->GetId() == 45062)
damageAmount += (*i)->GetModifier()->m_amount;
if (damageAmount)
m_caster->RemoveAurasDueToSpell(45062);
addhealth += damageAmount;
}
// Death Pact (percent heal)
else if (m_spellInfo->Id == 48743)
addhealth = addhealth * unitTarget->GetMaxHealth() / 100;
// Swiftmend - consumes Regrowth or Rejuvenation
else if (m_spellInfo->GetTargetAuraState() == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
{
Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
// find most short by duration
Aura* targetAura = NULL;
for (Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
{
SpellClassOptionsEntry const* smClassOptions = (*i)->GetSpellProto()->GetSpellClassOptions();
if (smClassOptions && smClassOptions->SpellFamilyName == SPELLFAMILY_DRUID &&
// Regrowth or Rejuvenation 0x40 | 0x10
(smClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000050)))
{
if (!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
targetAura = *i;
}
}
if (!targetAura)
{
sLog.outError("Target (GUID: %u TypeId: %u) has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUIDLow(), unitTarget->GetTypeId());
return;
}
int idx = 0;
SpellEffectEntry const* targetSpellEffect = NULL;
while(idx < 3)
{
targetSpellEffect = targetAura->GetSpellProto()->GetSpellEffect(SpellEffectIndex(idx));
if(targetSpellEffect && targetSpellEffect->EffectApplyAuraName == SPELL_AURA_PERIODIC_HEAL)
break;
++idx;
}
int32 tickheal = targetAura->GetModifier()->m_amount;
int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / (targetSpellEffect ? targetSpellEffect->EffectAmplitude : 1) - 1;
// Glyph of Swiftmend
if (!caster->HasAura(54824))
unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
addhealth += tickheal * tickcount;
}
// Runic Healing Injector & Healing Potion Injector effect increase for engineers
else if ((m_spellInfo->Id == 67486 || m_spellInfo->Id == 67489) && unitTarget->GetTypeId() == TYPEID_PLAYER)
{
Player* player = (Player*)unitTarget;
if (player->HasSkill(SKILL_ENGINEERING))
addhealth += int32(addhealth * 0.25);
}
// Chain Healing
SpellClassOptionsEntry const* chClassOptions = m_spellInfo->GetSpellClassOptions();
if (chClassOptions && chClassOptions->SpellFamilyName == SPELLFAMILY_SHAMAN && chClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000100))
{
if (unitTarget == m_targets.getUnitTarget())
{
// check for Riptide
Aura* riptide = unitTarget->GetAura(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, UI64LIT(0x0), 0x00000010, caster->GetObjectGuid());
if (riptide)
{
addhealth += addhealth / 4;
unitTarget->RemoveAurasDueToSpell(riptide->GetId());
}
}
}
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
m_healing += addhealth;
}
}
void Spell::EffectHealPct(SpellEffectEntry const* /*effect*/)
{
if (unitTarget && unitTarget->IsAlive() && damage >= 0)
{
// Try to get original caster
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
uint32 absorb = 0;
unitTarget->CalculateHealAbsorb(addhealth, &absorb);
int32 gain = caster->DealHeal(unitTarget, addhealth - absorb, m_spellInfo, false, absorb);
unitTarget->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(m_spellInfo), m_spellInfo);
}
}
void Spell::EffectHealMechanical(SpellEffectEntry const* /*effect*/)
{
// Mechanic creature type should be correctly checked by targetCreatureType field
if (unitTarget && unitTarget->IsAlive() && damage >= 0)
{
// Try to get original caster
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
uint32 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, damage, HEAL);
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
uint32 absorb = 0;
unitTarget->CalculateHealAbsorb(addhealth, &absorb);
caster->DealHeal(unitTarget, addhealth - absorb, m_spellInfo, false, absorb);
}
}
void Spell::EffectHealthLeech(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
if (damage < 0)
return;
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "HealthLeech :%i", damage);
uint32 curHealth = unitTarget->GetHealth();
damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage);
if ((int32)curHealth < damage)
damage = curHealth;
float multiplier = effect->EffectMultipleValue;
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
int32 heal = int32(damage * multiplier);
if (m_caster->IsAlive())
{
heal = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, heal, HEAL);
uint32 absorb = 0;
m_caster->CalculateHealAbsorb(heal, &absorb);
m_caster->DealHeal(m_caster, heal - absorb, m_spellInfo, false, absorb);
}
}
void Spell::DoCreateItem(SpellEffectEntry const* effect, uint32 itemtype)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)unitTarget;
uint32 newitemid = itemtype;
ItemPrototype const* pProto = ObjectMgr::GetItemPrototype(newitemid);
if (!pProto)
{
player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
// bg reward have some special in code work
bool bg_mark = false;
switch (m_spellInfo->Id)
{
case SPELL_WG_MARK_VICTORY:
case SPELL_WG_MARK_DEFEAT:
bg_mark = true;
break;
default:
break;
}
uint32 num_to_add = damage;
if (num_to_add < 1)
num_to_add = 1;
if (num_to_add > pProto->GetMaxStackSize())
num_to_add = pProto->GetMaxStackSize();
// init items_count to 1, since 1 item will be created regardless of specialization
int items_count = 1;
// the chance to create additional items
float additionalCreateChance = 0.0f;
// the maximum number of created additional items
uint8 additionalMaxNum = 0;
// get the chance and maximum number for creating extra items
if (canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum))
{
// roll with this chance till we roll not to create or we create the max num
while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum)
++items_count;
}
// really will be created more items
num_to_add *= items_count;
// can the player store the new item?
ItemPosCountVec dest;
uint32 no_space = 0;
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space);
if (msg != EQUIP_ERR_OK)
{
// convert to possible store amount
if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
num_to_add -= no_space;
else
{
// ignore mana gem case (next effect will recharge existing example)
if (effect->EffectIndex == EFFECT_INDEX_0 && m_spellInfo->GetSpellEffectIdByIndex(EFFECT_INDEX_1) == SPELL_EFFECT_DUMMY )
return;
// if not created by another reason from full inventory or unique items amount limitation
player->SendEquipError(msg, NULL, NULL, newitemid);
return;
}
}
if (num_to_add)
{
// create the new item and store it
Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
// was it successful? return error if not
if (!pItem)
{
player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
return;
}
// set the "Crafted by ..." property of the item
if (pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
pItem->SetGuidValue(ITEM_FIELD_CREATOR, player->GetObjectGuid());
// send info to the client
player->SendNewItem(pItem, num_to_add, true, !bg_mark);
// we succeeded in creating at least one item, so a levelup is possible
if (!bg_mark)
player->UpdateCraftSkill(m_spellInfo->Id);
}
}
void Spell::EffectCreateItem(SpellEffectEntry const* effect)
{
DoCreateItem(effect, effect->EffectItemType);
}
void Spell::EffectCreateItem2(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)m_caster;
// explicit item (possible fake)
uint32 item_id = effect->EffectItemType;
if (item_id)
DoCreateItem(effect, item_id);
// not explicit loot (with fake item drop if need)
if (IsLootCraftingSpell(m_spellInfo))
{
if (item_id)
{
if (!player->HasItemCount(item_id, 1))
return;
// remove reagent
uint32 count = 1;
player->DestroyItemCount(item_id, count, true);
}
// create some random items
player->AutoStoreLoot(NULL, m_spellInfo->Id, LootTemplates_Spell);
}
}
void Spell::EffectCreateRandomItem(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)m_caster;
// create some random items
player->AutoStoreLoot(NULL, m_spellInfo->Id, LootTemplates_Spell);
}
void Spell::EffectPersistentAA(SpellEffectEntry const* effect)
{
Unit* pCaster = GetAffectiveCaster();
// FIXME: in case wild GO will used wrong affective caster (target in fact) as dynobject owner
if (!pCaster)
pCaster = m_caster;
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
if (Player* modOwner = pCaster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
DynamicObject* dynObj = new DynamicObject;
if (!dynObj->Create(pCaster->GetMap()->GenerateLocalLowGuid(HIGHGUID_DYNAMICOBJECT), pCaster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, m_duration, radius, DYNAMIC_OBJECT_AREA_SPELL))
{
delete dynObj;
return;
}
pCaster->AddDynObject(dynObj);
pCaster->GetMap()->Add(dynObj);
}
void Spell::EffectEnergize(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
if(effect->EffectMiscValue < 0 || effect->EffectMiscValue >= MAX_POWERS)
return;
Powers power = Powers(effect->EffectMiscValue);
// Some level depends spells
int level_multiplier = 0;
int level_diff = 0;
switch (m_spellInfo->Id)
{
case 9512: // Restore Energy
level_diff = m_caster->getLevel() - 40;
level_multiplier = 2;
break;
case 24571: // Blood Fury
level_diff = m_caster->getLevel() - 60;
level_multiplier = 10;
break;
case 24532: // Burst of Energy
level_diff = m_caster->getLevel() - 60;
level_multiplier = 4;
break;
case 31930: // Judgements of the Wise
case 48542: // Revitalize (mana restore case)
case 63375: // Improved Stormstrike
case 68082: // Glyph of Seal of Command
damage = damage * unitTarget->GetCreateMana() / 100;
break;
case 67487: // Mana Potion Injector
case 67490: // Runic Mana Injector
{
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
Player* player = (Player*)unitTarget;
if (player->HasSkill(SKILL_ENGINEERING))
damage += int32(damage * 0.25);
}
break;
}
default:
break;
}
if (level_diff > 0)
damage -= level_multiplier * level_diff;
if (damage < 0)
return;
if (unitTarget->GetMaxPower(power) == 0)
return;
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
// Mad Alchemist's Potion
if (m_spellInfo->Id == 45051)
{
// find elixirs on target
uint32 elixir_mask = 0;
Unit::SpellAuraHolderMap& Auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
{
uint32 spell_id = itr->second->GetId();
if (uint32 mask = sSpellMgr.GetSpellElixirMask(spell_id))
elixir_mask |= mask;
}
// get available elixir mask any not active type from battle/guardian (and flask if no any)
elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
// get all available elixirs by mask and spell level
std::vector<uint32> elixirs;
SpellElixirMap const& m_spellElixirs = sSpellMgr.GetSpellElixirMap();
for (SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
{
if (itr->second & elixir_mask)
{
if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo && (spellInfo->GetSpellLevel() < m_spellInfo->GetSpellLevel() || spellInfo->GetSpellLevel() > unitTarget->getLevel()))
continue;
elixirs.push_back(itr->first);
}
}
if (!elixirs.empty())
{
// cast random elixir on target
uint32 rand_spell = urand(0, elixirs.size() - 1);
m_caster->CastSpell(unitTarget, elixirs[rand_spell], true, m_CastItem);
}
}
}
void Spell::EffectEnergisePct(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
if (effect->EffectMiscValue < 0 || effect->EffectMiscValue >= MAX_POWERS)
return;
Powers power = Powers(effect->EffectMiscValue);
uint32 maxPower = unitTarget->GetMaxPower(power);
if (maxPower == 0)
return;
uint32 gain = damage * maxPower / 100;
m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power);
}
void Spell::SendLoot(ObjectGuid guid, LootType loottype, LockType lockType)
{
if (gameObjTarget)
{
switch (gameObjTarget->GetGoType())
{
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
case GAMEOBJECT_TYPE_QUESTGIVER:
case GAMEOBJECT_TYPE_SPELL_FOCUS:
case GAMEOBJECT_TYPE_GOOBER:
gameObjTarget->Use(m_caster);
return;
case GAMEOBJECT_TYPE_CHEST:
gameObjTarget->Use(m_caster);
// Don't return, let loots been taken
break;
case GAMEOBJECT_TYPE_TRAP:
if (lockType == LOCKTYPE_DISARM_TRAP)
{
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
return;
}
sLog.outError("Spell::SendLoot unhandled locktype %u for GameObject trap (entry %u) for spell %u.", lockType, gameObjTarget->GetEntry(), m_spellInfo->Id);
return;
default:
sLog.outError("Spell::SendLoot unhandled GameObject type %u (entry %u) for spell %u.", gameObjTarget->GetGoType(), gameObjTarget->GetEntry(), m_spellInfo->Id);
return;
}
}
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Send loot
((Player*)m_caster)->SendLoot(guid, loottype);
}
void Spell::EffectOpenLock(SpellEffectEntry const* effect)
{
if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
{
DEBUG_LOG("WORLD: Open Lock - No Player Caster!");
return;
}
Player* player = (Player*)m_caster;
uint32 lockId = 0;
ObjectGuid guid;
// Get lockId
if (gameObjTarget)
{
GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
// Arathi Basin banner opening !
if ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) ||
(goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK))
{
// CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if (BattleGround* bg = player->GetBattleGround())
{
// check if it's correct bg
if (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_AV)
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
return;
}
}
else if (goInfo->type == GAMEOBJECT_CreatureTypeFlagsTAND)
{
// CanUseBattleGroundObject() already called in CheckCast()
// in battleground check
if (BattleGround* bg = player->GetBattleGround())
{
if (bg->GetTypeID() == BATTLEGROUND_EY)
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
return;
}
}
lockId = goInfo->GetLockId();
guid = gameObjTarget->GetObjectGuid();
}
else if (itemTarget)
{
lockId = itemTarget->GetProto()->LockID;
guid = itemTarget->GetObjectGuid();
}
else
{
DEBUG_LOG("WORLD: Open Lock - No GameObject/Item Target!");
return;
}
SkillType skillId = SKILL_NONE;
int32 reqSkillValue = 0;
int32 skillValue;
SpellCastResult res = CanOpenLock(SpellEffectIndex(effect->EffectIndex), lockId, skillId, reqSkillValue, skillValue);
if (res != SPELL_CAST_OK)
{
SendCastResult(res);
return;
}
// mark item as unlocked
if (itemTarget)
itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_UNLOCKED);
SendLoot(guid, LOOT_SKINNING, LockType(effect->EffectMiscValue));
// not allow use skill grow at item base open
if (!m_CastItem && skillId != SKILL_NONE)
{
// update skill if really known
if (uint32 pureSkillValue = player->GetPureSkillValue(skillId))
{
if (gameObjTarget)
{
// Allow one skill-up until respawned
if (!gameObjTarget->IsInSkillupList(player) &&
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue))
gameObjTarget->AddToSkillupList(player);
}
else if (itemTarget)
{
// Do one skill-up
player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
}
}
}
}
void Spell::EffectSummonChangeItem(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)m_caster;
// applied only to using item
if (!m_CastItem)
return;
// ... only to item in own inventory/bank/equip_slot
if (m_CastItem->GetOwnerGuid() != player->GetObjectGuid())
return;
uint32 newitemid = effect->EffectItemType;
if (!newitemid)
return;
Item* oldItem = m_CastItem;
// prevent crash at access and unexpected charges counting with item update queue corrupt
ClearCastItem();
player->ConvertItem(oldItem, newitemid);
}
void Spell::EffectProficiency(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player *p_target = (Player*)unitTarget;
SpellEquippedItemsEntry const* eqItems = m_spellInfo->GetSpellEquippedItems();
if (!eqItems)
return;
if (eqItems->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & eqItems->EquippedItemSubClassMask))
{
p_target->AddWeaponProficiency(eqItems->EquippedItemSubClassMask);
p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency());
}
if (eqItems->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & eqItems->EquippedItemSubClassMask))
{
p_target->AddArmorProficiency(eqItems->EquippedItemSubClassMask);
p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency());
}
}
void Spell::EffectApplyAreaAura(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
AreaAura* Aur = new AreaAura(m_spellInfo, SpellEffectIndex(effect->EffectIndex), &m_currentBasePoints[effect->EffectIndex], m_spellAuraHolder, unitTarget, m_caster, m_CastItem);
m_spellAuraHolder->AddAura(Aur, SpellEffectIndex(effect->EffectIndex));
}
void Spell::EffectSummonType(SpellEffectEntry const* effect)
{
// if this spell already have an aura applied cancel the summon
if (m_caster->HasAura(m_spellInfo->Id))
return;
uint32 prop_id = effect->EffectMiscValueB;
SummonPropertiesEntry const *summon_prop = sSummonPropertiesStore.LookupEntry(prop_id);
if(!summon_prop)
{
sLog.outError("EffectSummonType: Unhandled summon type %u", prop_id);
return;
}
// Pet's are atm handled differently
if (summon_prop->Group == SUMMON_PROP_GROUP_PETS && prop_id != 1562)
{
DoSummonPet(effect);
}
// Expected Amount: TODO - there are quite some exceptions (like totems, engineering dragonlings..)
uint32 amount = damage > 0 ? damage : 1;
// basepoints of SUMMON_PROP_GROUP_VEHICLE is often a spellId, set amount to 1
if (summon_prop->Group == SUMMON_PROP_GROUP_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE || summon_prop->Group == SUMMON_PROP_GROUP_CONTROLLABLE)
amount = 1;
// Get casting object
WorldObject* realCaster = GetCastingObject();
if (!realCaster)
{
sLog.outError("EffectSummonType: No Casting Object found for spell %u, (caster = %s)", m_spellInfo->Id, m_caster->GetGuidStr().c_str());
return;
}
Unit* responsibleCaster = m_originalCaster;
if (realCaster->GetTypeId() == TYPEID_GAMEOBJECT)
responsibleCaster = ((GameObject*)realCaster)->GetOwner();
// Expected Level (Totem, Pet and Critter may not use this)
uint32 level = responsibleCaster ? responsibleCaster->getLevel() : m_caster->getLevel();
// level of creature summoned using engineering item based at engineering skill level
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_CastItem)
{
ItemPrototype const* proto = m_CastItem->GetProto();
if (proto && proto->RequiredSkill == SKILL_ENGINEERING)
if (uint16 engineeringSkill = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINEERING))
{
level = engineeringSkill / 5;
amount = 1; // TODO HACK (needs a neat way of doing)
}
}
CreatureSummonPositions summonPositions;
summonPositions.resize(amount, CreaturePosition());
// Set middle position
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z);
else
{
realCaster->GetPosition(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z);
// TODO - Is this really an error?
sLog.outDebug("Spell Effect EFFECT_SUMMON (%u) - summon without destination (spell id %u, effIndex %u)", effect->Effect, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex));
}
// Set summon positions
float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
CreatureSummonPositions::iterator itr = summonPositions.begin();
for (++itr; itr != summonPositions.end(); ++itr) // In case of multiple summons around position for not-fist positions
{
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION || radius > 1.0f)
{
realCaster->GetRandomPoint(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, radius, itr->x, itr->y, itr->z);
if (realCaster->GetMap()->GetHitPosition(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, itr->x, itr->y, itr->z, m_caster->GetPhaseMask(), -0.5f))
realCaster->UpdateAllowedPositionZ(itr->x, itr->y, itr->z);
}
else // Get a point near the caster
{
realCaster->GetRandomPoint(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, radius, itr->x, itr->y, itr->z);
if (realCaster->GetMap()->GetHitPosition(summonPositions[0].x, summonPositions[0].y, summonPositions[0].z, itr->x, itr->y, itr->z, m_caster->GetPhaseMask(), -0.5f))
realCaster->UpdateAllowedPositionZ(itr->x, itr->y, itr->z);
}
}
bool summonResult = false;
switch (summon_prop->Group)
{
// faction handled later on, or loaded from template
case SUMMON_PROP_GROUP_WILD:
case SUMMON_PROP_GROUP_FRIENDLY:
{
switch (summon_prop->Title) // better from known way sorting summons by AI types
{
case UNITNAME_SUMMON_TITLE_NONE:
{
// those are classical totems - effectbasepoints is their hp and not summon ammount!
// 121: 23035, battlestands
// 647: 52893, Anti-Magic Zone (npc used)
if (prop_id == 121 || prop_id == 647)
summonResult = DoSummonTotem(effect);
else
summonResult = DoSummonWild(summonPositions, summon_prop, effect, level);
break;
}
case UNITNAME_SUMMON_TITLE_PET:
case UNITNAME_SUMMON_TITLE_MINION:
case UNITNAME_SUMMON_TITLE_RUNEBLADE:
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
break;
case UNITNAME_SUMMON_TITLE_GUARDIAN:
{
if (prop_id == 61) // mixed guardians, totems, statues
{
// * Stone Statue, etc -- fits much better totem AI
if (m_spellInfo->SpellIconID == 2056)
summonResult = DoSummonTotem(effect);
else
{
// possible sort totems/guardians only by summon creature type
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(effect->EffectMiscValue);
if (!cInfo)
return;
// FIXME: not all totems and similar cases selected by this check...
if (cInfo->CreatureType == CREATURE_TYPE_TOTEM)
summonResult = DoSummonTotem(effect);
else
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
}
}
else
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
break;
}
case UNITNAME_SUMMON_TITLE_CONSTRUCT:
{
if (prop_id == 2913) // Scrapbot
summonResult = DoSummonWild(summonPositions, summon_prop, effect, level);
else
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
break;
}
case UNITNAME_SUMMON_TITLE_TOTEM:
summonResult = DoSummonTotem(effect, summon_prop->Slot);
break;
case UNITNAME_SUMMON_TITLE_COMPANION:
// slot 6 set for critters that can help to player in fighting
if (summon_prop->Slot == 6)
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
else
summonResult = DoSummonCritter(summonPositions, summon_prop, effect, level);
break;
case UNITNAME_SUMMON_TITLE_OPPONENT:
case UNITNAME_SUMMON_TITLE_VEHICLE:
case UNITNAME_SUMMON_TITLE_MOUNT:
case UNITNAME_SUMMON_TITLE_LIGHTWELL:
case UNITNAME_SUMMON_TITLE_BUTLER:
summonResult = DoSummonWild(summonPositions, summon_prop, effect, level);
break;
default:
sLog.outError("EffectSummonType: Unhandled summon title %u", summon_prop->Title);
break;
}
break;
}
case SUMMON_PROP_GROUP_PETS:
{
// FIXME : multiple summons - not yet supported as pet
// 1562 - force of nature - sid 33831
// 1161 - feral spirit - sid 51533
if (prop_id == 1562) // 3 uncontrolable instead of one controllable :/
summonResult = DoSummonGuardian(summonPositions, summon_prop, effect, level);
break;
}
case SUMMON_PROP_GROUP_CONTROLLABLE:
{
summonResult = DoSummonPossessed(summonPositions, summon_prop, effect, level);
break;
}
case SUMMON_PROP_GROUP_VEHICLE:
case SUMMON_PROP_GROUP_UNCONTROLLABLE_VEHICLE:
{
summonResult = DoSummonVehicle(summonPositions, summon_prop, effect, level);
break;
}
default:
sLog.outError("EffectSummonType: Unhandled summon group type %u", summon_prop->Group);
break;
}
if (!summonResult)
return; // No further handling required
for (itr = summonPositions.begin(); itr != summonPositions.end(); ++itr)
{
MANGOS_ASSERT(itr->creature || itr != summonPositions.begin());
if (!itr->creature)
{
sLog.outError("EffectSummonType: Expected to have %u NPCs summoned, but some failed (Spell id %u)", amount, m_spellInfo->Id);
continue;
}
if (summon_prop->FactionId)
itr->creature->setFaction(summon_prop->FactionId);
// Else set faction to summoner's faction for pet-like summoned
else if ((summon_prop->Flags & SUMMON_PROP_FLAG_INHERIT_FACTION) || !itr->creature->IsTemporarySummon())
itr->creature->setFaction(responsibleCaster ? responsibleCaster->getFaction() : m_caster->getFaction());
if (!itr->creature->IsTemporarySummon())
{
itr->creature->AIM_Initialize();
m_caster->GetMap()->Add(itr->creature);
// Notify Summoner
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
((Creature*)m_caster)->AI()->JustSummoned(itr->creature);
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(itr->creature);
}
}
}
bool Spell::DoSummonWild(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level)
{
MANGOS_ASSERT(!list.empty() && prop);
uint32 creature_entry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(creature_entry);
if (!cInfo)
{
sLog.outErrorDb("Spell::DoSummonWild: creature entry %u not found for spell %u.", creature_entry, m_spellInfo->Id);
return false;
}
TempSummonType summonType = (m_duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN;
for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
if (Creature* summon = m_caster->SummonCreature(creature_entry, itr->x, itr->y, itr->z, m_caster->GetOrientation(), summonType, m_duration))
{
itr->creature = summon;
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
// UNIT_FIELD_CREATEDBY are not set for these kind of spells.
// Does exceptions exist? If so, what are they?
// summon->SetCreatorGuid(m_caster->GetObjectGuid());
// Notify original caster if not done already
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(summon);
}
else
return false;
return true;
}
bool Spell::DoSummonCritter(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 /*level*/)
{
MANGOS_ASSERT(!list.empty() && prop);
// ATM only first position is supported for summoning
uint32 pet_entry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(pet_entry);
if (!cInfo)
{
sLog.outErrorDb("Spell::DoSummonCritter: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
return false;
}
Pet* old_critter = m_caster->GetMiniPet();
// for same pet just despawn (player unsummon command)
if (m_caster->GetTypeId() == TYPEID_PLAYER && old_critter && old_critter->GetEntry() == pet_entry)
{
m_caster->RemoveMiniPet();
return false;
}
// despawn old pet before summon new
if (old_critter)
m_caster->RemoveMiniPet();
// for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
CreatureCreatePos pos(m_caster->GetMap(), list[0].x, list[0].y, list[0].z, m_caster->GetOrientation(), m_caster->GetPhaseMask());
// summon new pet
Pet* critter = new Pet(MINI_PET);
uint32 pet_number = sObjectMgr.GeneratePetNumber();
if (!critter->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
{
sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
delete critter;
return false;
}
// itr!
list[0].creature = critter;
critter->SetRespawnCoord(pos);
// critter->SetName(""); // generated by client
critter->SetOwnerGuid(m_caster->GetObjectGuid());
critter->SetCreatorGuid(m_caster->GetObjectGuid());
critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
// critter->InitLevelupSpellsForLevel(); // none?
critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->NpcFlags);
// some mini-pets have quests
// set timer for unsummon
if (m_duration > 0)
critter->SetDuration(m_duration);
m_caster->SetMiniPet(critter);
return true;
}
bool Spell::DoSummonGuardian(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level)
{
MANGOS_ASSERT(!list.empty() && prop);
uint32 pet_entry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(pet_entry);
if (!cInfo)
{
sLog.outErrorDb("Spell::DoSummonGuardian: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
return false;
}
PetType petType = prop->Title == UNITNAME_SUMMON_TITLE_COMPANION ? PROTECTOR_PET : GUARDIAN_PET;
// second direct cast unsummon guardian(s) (guardians without like functionality have cooldown > spawn time)
if (!m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER)
{
bool found = false;
// including protector
while (Pet* old_summon = m_caster->FindGuardianWithEntry(pet_entry))
{
old_summon->Unsummon(PET_SAVE_AS_DELETED, m_caster);
found = true;
}
if (found)
return false;
}
// protectors allowed only in single amount
if (petType == PROTECTOR_PET)
if (Pet* old_protector = m_caster->GetProtectorPet())
old_protector->Unsummon(PET_SAVE_AS_DELETED, m_caster);
// in another case summon new
for (CreatureSummonPositions::iterator itr = list.begin(); itr != list.end(); ++itr)
{
Pet* spawnCreature = new Pet(petType);
CreatureCreatePos pos(m_caster->GetMap(), itr->x, itr->y, itr->z, -m_caster->GetOrientation(), m_caster->GetPhaseMask());
uint32 pet_number = sObjectMgr.GeneratePetNumber();
if (!spawnCreature->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
{
sLog.outError("Spell::DoSummonGuardian: can't create creature entry %u for spell %u.", pet_entry, m_spellInfo->Id);
delete spawnCreature;
return false;
}
itr->creature = spawnCreature;
spawnCreature->SetRespawnCoord(pos);
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
CreatureInfo const* cInfo = spawnCreature->GetCreatureInfo();
// spawnCreature->SetName(""); // generated by client
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, cInfo->UnitFlags);
spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, cInfo->NpcFlags);
spawnCreature->setFaction(m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
spawnCreature->InitStatsForLevel(level);
if (CharmInfo* charmInfo = spawnCreature->GetCharmInfo())
{
charmInfo->SetPetNumber(pet_number, false);
if (spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE))
charmInfo->SetReactState(REACT_PASSIVE);
else if ((cInfo->ExtraFlags & CREATURE_EXTRA_FLAG_NO_MELEE) || petType == PROTECTOR_PET)
charmInfo->SetReactState(REACT_DEFENSIVE);
else
charmInfo->SetReactState(REACT_AGGRESSIVE);
}
m_caster->AddGuardian(spawnCreature);
}
return true;
}
bool Spell::DoSummonTotem(SpellEffectEntry const* effect, uint8 slot_dbc)
{
// DBC store slots starting from 1, with no slot 0 value)
int slot = slot_dbc ? slot_dbc - 1 : TOTEM_SLOT_NONE;
// unsummon old totem
if (slot < MAX_TOTEM_SLOT)
if (Totem* OldTotem = m_caster->GetTotem(TotemSlot(slot)))
OldTotem->UnSummon();
// FIXME: Setup near to finish point because GetObjectBoundingRadius set in Create but some Create calls can be dependent from proper position
// if totem have creature_template_addon.auras with persistent point for example or script call
float angle = slot < MAX_TOTEM_SLOT ? M_PI_F / MAX_TOTEM_SLOT - (slot * 2 * M_PI_F / MAX_TOTEM_SLOT) : 0;
CreatureCreatePos pos(m_caster, m_caster->GetOrientation(), 2.0f, angle);
CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(effect->EffectMiscValue);
if (!cinfo)
{
sLog.outErrorDb("Creature entry %u does not exist but used in spell %u totem summon.", m_spellInfo->Id, effect->EffectMiscValue);
return false;
}
Totem* pTotem = new Totem;
if (!pTotem->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_UNIT), pos, cinfo, m_caster))
{
delete pTotem;
return false;
}
pTotem->SetRespawnCoord(pos);
if (slot < MAX_TOTEM_SLOT)
m_caster->_AddTotem(TotemSlot(slot), pTotem);
// pTotem->SetName(""); // generated by client
pTotem->SetOwner(m_caster);
pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initialized
pTotem->SetDuration(m_duration);
if (damage) // if not spell info, DB values used
{
pTotem->SetMaxHealth(damage);
pTotem->SetHealth(damage);
}
pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
pTotem->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
if (m_caster->IsPvP())
pTotem->SetPvP(true);
if (m_caster->IsFFAPvP())
pTotem->SetFFAPvP(true);
// sending SMSG_TOTEM_CREATED before add to map (done in Summon)
if (slot < MAX_TOTEM_SLOT && m_caster->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_TOTEM_CREATED, 1 + 8 + 4 + 4);
data << uint8(slot);
data << pTotem->GetObjectGuid();
data << uint32(m_duration);
data << uint32(m_spellInfo->Id);
((Player*)m_caster)->SendDirectMessage(&data);
}
pTotem->Summon(m_caster);
return false;
}
bool Spell::DoSummonPossessed(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const* effect, uint32 level)
{
MANGOS_ASSERT(!list.empty() && prop);
uint32 const& creatureEntry = effect->EffectMiscValue;
Unit* newUnit = m_caster->TakePossessOf(m_spellInfo, prop, effect, list[0].x, list[0].y, list[0].z, m_caster->GetOrientation());
if (!newUnit)
{
sLog.outError("Spell::DoSummonPossessed: creature entry %d for spell %u could not be summoned.", creatureEntry, m_spellInfo->Id);
return false;
}
list[0].creature = static_cast<Creature*>(newUnit);
// Notify Summoner
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(list[0].creature);
return true;
}
bool Spell::DoSummonPet(SpellEffectEntry const* effect)
{
if (m_caster->GetPetGuid())
return false;
if (!unitTarget)
return false;
uint32 pet_entry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(pet_entry);
if (!cInfo)
{
sLog.outErrorDb("Spell::DoSummonPet: creature entry %u not found for spell %u.", pet_entry, m_spellInfo->Id);
return false;
}
Pet* spawnCreature = new Pet();
// set timer for unsummon
if (m_duration > 0)
spawnCreature->SetDuration(m_duration);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
if (spawnCreature->LoadPetFromDB((Player*)m_caster, pet_entry))
{
// Summon in dest location
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
spawnCreature->Relocate(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation());
return true;
}
spawnCreature->setPetType(SUMMON_PET);
}
else
spawnCreature->setPetType(GUARDIAN_PET);
// Summon in dest location
CreatureCreatePos pos(m_caster->GetMap(), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, -m_caster->GetOrientation(), m_caster->GetPhaseMask());
if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
pos = CreatureCreatePos(m_caster, -m_caster->GetOrientation());
Map* map = m_caster->GetMap();
uint32 pet_number = sObjectMgr.GeneratePetNumber();
if (!spawnCreature->Create(map->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
{
sLog.outErrorDb("Spell::EffectSummon: can't create creature with entry %u for spell %u", cInfo->Entry, m_spellInfo->Id);
delete spawnCreature;
return false;
}
uint32 level = std::max(m_caster->getLevel() + effect->EffectMultipleValue, 1.0f);
spawnCreature->SetRespawnCoord(pos);
spawnCreature->SetOwnerGuid(m_caster->GetObjectGuid());
spawnCreature->setFaction(m_caster->getFaction());
spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
spawnCreature->InitStatsForLevel(level);
spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
spawnCreature->InitPetCreateSpells();
spawnCreature->InitLevelupSpellsForLevel();
// spawnCreature->SetName(""); // generated by client
map->Add((Creature*)spawnCreature);
spawnCreature->AIM_Initialize();
m_caster->SetPet(spawnCreature);
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
spawnCreature->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
((Player*)m_caster)->PetSpellInitialize();
}
else
{
// Notify Summoner
if (m_originalCaster && (m_originalCaster != m_caster)
&& (m_originalCaster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_originalCaster)->AI())
{
((Creature*)m_originalCaster)->AI()->JustSummoned(spawnCreature);
if (m_originalCaster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)spawnCreature)->AI()->AttackStart(m_originalCaster->getAttackerForHelper());
}
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_caster)->AI())
{
((Creature*)m_caster)->AI()->JustSummoned(spawnCreature);
if (m_caster->IsInCombat() && !(spawnCreature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)spawnCreature)->AI()->AttackStart(m_caster->getAttackerForHelper());
}
}
return true;
}
bool Spell::DoSummonVehicle(CreatureSummonPositions& list, SummonPropertiesEntry const* prop, SpellEffectEntry const * effect, uint32 /*level*/)
{
MANGOS_ASSERT(!list.empty() && prop);
uint32 creatureEntry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(creatureEntry);
if (!cInfo)
{
sLog.outErrorDb("Spell::DoSummonVehicle: creature entry %u not found for spell %u.", creatureEntry, m_spellInfo->Id);
return false;
}
Creature* spawnCreature = m_caster->SummonCreature(creatureEntry, list[0].x, list[0].y, list[0].z, m_caster->GetOrientation(),
(m_duration == 0) ? TEMPSUMMON_CORPSE_DESPAWN : TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN, m_duration);
if (!spawnCreature)
{
sLog.outError("Spell::DoSummonVehicle: creature entry %u for spell %u could not be summoned.", creatureEntry, m_spellInfo->Id);
return false;
}
list[0].creature = spawnCreature;
// Changes to be sent
spawnCreature->SetCreatorGuid(m_caster->GetObjectGuid());
spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
//spawnCreature->SetLevel(level); // Do we need to set level for vehicles?
// Board the caster right after summoning
SpellEntry const* controlSpellEntry = sSpellStore.LookupEntry(effect->CalculateSimpleValue());
if (controlSpellEntry && IsSpellHaveAura(controlSpellEntry, SPELL_AURA_CONTROL_VEHICLE))
m_caster->CastSpell(spawnCreature, controlSpellEntry, true);
else
m_caster->CastSpell(spawnCreature, SPELL_RIDE_VEHICLE_HARDCODED, true);
// If the boarding failed...
if (!spawnCreature->HasAuraType(SPELL_AURA_CONTROL_VEHICLE))
{
spawnCreature->ForcedDespawn();
return false;
}
// Notify Summoner
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(spawnCreature);
return true;
}
void Spell::EffectLearnSpell(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
EffectLearnPetSpell(effect);
return;
}
Player* player = (Player*)unitTarget;
uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : effect->EffectTriggerSpell;
player->learnSpell(spellToLearn, false);
if (WorldObject const* caster = GetCastingObject())
DEBUG_LOG("Spell: %s has learned spell %u from %s", player->GetGuidStr().c_str(), spellToLearn, caster->GetGuidStr().c_str());
}
void Spell::EffectDispel(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
// Fill possible dispel list
std::list <std::pair<SpellAuraHolder* , uint32> > dispel_list;
// Create dispel mask by dispel type
uint32 dispel_type = effect->EffectMiscValue;
uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellAuraHolder *holder = itr->second;
if ((1<<holder->GetSpellProto()->GetDispel()) & dispelMask)
{
if(holder->GetSpellProto()->GetDispel() == DISPEL_MAGIC)
{
bool positive = true;
if (!holder->IsPositive())
positive = false;
else
positive = !holder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX_NEGATIVE);
// do not remove positive auras if friendly target
// negative auras if non-friendly target
if (positive == unitTarget->IsFriendlyTo(m_caster))
continue;
}
// Unholy Blight prevents dispel of diseases from target
else if (holder->GetSpellProto()->GetDispel() == DISPEL_DISEASE)
if (unitTarget->HasAura(50536))
continue;
dispel_list.push_back(std::pair<SpellAuraHolder* , uint32>(holder, holder->GetStackAmount()));
}
}
// Ok if exist some buffs for dispel try dispel it
if (!dispel_list.empty())
{
std::list<std::pair<SpellAuraHolder* , uint32> > success_list; // (spell_id,casterGuid)
std::list < uint32 > fail_list; // spell_id
// some spells have effect value = 0 and all from its by meaning expect 1
if (!damage)
damage = 1;
// Dispel N = damage buffs (or while exist buffs for dispel)
for (int32 count = 0; count < damage && !dispel_list.empty(); ++count)
{
// Random select buff for dispel
std::list<std::pair<SpellAuraHolder* , uint32> >::iterator dispel_itr = dispel_list.begin();
std::advance(dispel_itr, urand(0, dispel_list.size() - 1));
SpellAuraHolder* holder = dispel_itr->first;
dispel_itr->second -= 1;
// remove entry from dispel_list if nothing left in stack
if (dispel_itr->second == 0)
dispel_list.erase(dispel_itr);
SpellEntry const* spellInfo = holder->GetSpellProto();
// Base dispel chance
// TODO: possible chance depend from spell level??
int32 miss_chance = 0;
// Apply dispel mod from aura caster
if (Unit* caster = holder->GetCaster())
{
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
}
// Try dispel
if (roll_chance_i(miss_chance))
fail_list.push_back(spellInfo->Id);
else
{
bool foundDispelled = false;
for (std::list<std::pair<SpellAuraHolder* , uint32> >::iterator success_iter = success_list.begin(); success_iter != success_list.end(); ++success_iter)
{
if (success_iter->first->GetId() == holder->GetId() && success_iter->first->GetCasterGuid() == holder->GetCasterGuid())
{
success_iter->second += 1;
foundDispelled = true;
break;
}
}
if (!foundDispelled)
success_list.push_back(std::pair<SpellAuraHolder* , uint32>(holder, 1));
}
}
// Send success log and really remove auras
if (!success_list.empty())
{
int32 count = success_list.size();
WorldPacket data(SMSG_SPELLDISPELLOG, 8 + 8 + 4 + 1 + 4 + count * 5);
data << unitTarget->GetPackGUID(); // Victim GUID
data << m_caster->GetPackGUID(); // Caster GUID
data << uint32(m_spellInfo->Id); // Dispel spell id
data << uint8(0); // not used
data << uint32(count); // count
for (std::list<std::pair<SpellAuraHolder* , uint32> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
{
SpellAuraHolder* dispelledHolder = j->first;
data << uint32(dispelledHolder->GetId()); // Spell Id
data << uint8(0); // 0 - dispelled !=0 cleansed
unitTarget->RemoveAuraHolderDueToSpellByDispel(dispelledHolder->GetId(), j->second, dispelledHolder->GetCasterGuid(), m_caster);
}
m_caster->SendMessageToSet(&data, true);
// On success dispel
// Devour Magic
if (m_spellInfo->GetSpellFamilyName() == SPELLFAMILY_WARLOCK && m_spellInfo->GetCategory() == SPELLCATEGORY_DEVOUR_MAGIC)
{
int32 heal_amount = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1);
m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true);
}
}
// Send fail log to client
if (!fail_list.empty())
{
// Failed to dispel
WorldPacket data(SMSG_DISPEL_FAILED, 8 + 8 + 4 + 4 * fail_list.size());
data << m_caster->GetObjectGuid(); // Caster GUID
data << unitTarget->GetObjectGuid(); // Victim GUID
data << uint32(m_spellInfo->Id); // Dispel spell id
for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
data << uint32(*j); // Spell Id
m_caster->SendMessageToSet(&data, true);
}
}
}
void Spell::EffectDualWield(SpellEffectEntry const* /*effect*/)
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->SetCanDualWield(true);
}
void Spell::EffectPull(SpellEffectEntry const* /*effect*/)
{
// TODO: create a proper pull towards distract spell center for distract
DEBUG_LOG("WORLD: Spell Effect DUMMY");
}
void Spell::EffectDistract(SpellEffectEntry const* /*effect*/)
{
// Check for possible target
if (!unitTarget || unitTarget->IsInCombat())
return;
// target must be OK to do this
if (unitTarget->hasUnitState(UNIT_STAT_CAN_NOT_REACT))
return;
unitTarget->SetFacingTo(unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY));
unitTarget->clearUnitState(UNIT_STAT_MOVING);
if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
}
void Spell::EffectPickPocket(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// victim must be creature and attackable
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget))
return;
// victim have to be alive and humanoid or undead
if (unitTarget->IsAlive() && (unitTarget->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
{
int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
if (chance > irand(0, 19))
{
// Stealing successful
// DEBUG_LOG("Sending loot from pickpocket");
((Player*)m_caster)->SendLoot(unitTarget->GetObjectGuid(), LOOT_PICKPOCKETING);
}
else
{
// Reveal action + get attack
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
unitTarget->AttackedBy(m_caster);
}
}
}
void Spell::EffectAddFarsight(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
int32 duration = GetSpellDuration(m_spellInfo);
DynamicObject* dynObj = new DynamicObject;
// set radius to 0: spell not expected to work as persistent aura
if(!dynObj->Create(m_caster->GetMap()->GenerateLocalLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, 0, DYNAMIC_OBJECT_FARSIGHT_FOCUS))
{
delete dynObj;
return;
}
m_caster->AddDynObject(dynObj);
m_caster->GetMap()->Add(dynObj);
((Player*)m_caster)->GetCamera().SetView(dynObj);
}
void Spell::EffectTeleUnitsFaceCaster(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (unitTarget->IsTaxiFlying())
return;
float fx, fy, fz;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(fx, fy, fz);
else
{
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectBoundingRadius(), dis);
}
unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
}
void Spell::EffectLearnSkill(SpellEffectEntry const* effect)
{
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (damage < 0)
return;
uint32 skillid = effect->EffectMiscValue;
uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
((Player*)unitTarget)->SetSkill(skillid, skillval ? skillval : 1, damage * 75, damage);
if (WorldObject const* caster = GetCastingObject())
DEBUG_LOG("Spell: %s has learned skill %u (to maxlevel %u) from %s", unitTarget->GetGuidStr().c_str(), skillid, damage * 75, caster->GetGuidStr().c_str());
}
void Spell::EffectTradeSkill(SpellEffectEntry const* /*effect*/)
{
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// uint32 skillid = m_spellInfo->EffectMiscValue[i];
// uint16 skillmax = ((Player*)unitTarget)->(skillid);
// ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
}
void Spell::EffectEnchantItemPerm(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (!itemTarget)
return;
uint32 enchant_id = effect->EffectMiscValue;
if (!enchant_id)
return;
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if (!pEnchant)
return;
// item can be in trade slot and have owner diff. from caster
Player* item_owner = itemTarget->GetOwner();
if (!item_owner)
return;
Player* p_caster = (Player*)m_caster;
// Enchanting a vellum requires special handling, as it creates a new item
// instead of modifying an existing one.
ItemPrototype const* targetProto = itemTarget->GetProto();
if (targetProto->IsVellum() && effect->EffectItemType)
{
unitTarget = m_caster;
DoCreateItem(effect, effect->EffectItemType);
// Vellum target case: Target becomes additional reagent, new scroll item created instead in Spell::EffectEnchantItemPerm()
// cannot already delete in TakeReagents() unfortunately
p_caster->DestroyItemCount(targetProto->ItemId, 1, true);
return;
}
// Using enchant stored on scroll does not increase enchanting skill! (Already granted on scroll creation)
if (!(m_CastItem && m_CastItem->GetProto()->Flags & ITEM_FLAG_ENCHANT_SCROLL))
p_caster->UpdateCraftSkill(m_spellInfo->Id);
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
sLog.outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
p_caster->GetName(), p_caster->GetSession()->GetAccountId(),
itemTarget->GetProto()->Name1, itemTarget->GetEntry(),
item_owner->GetName(), item_owner->GetSession()->GetAccountId());
}
// remove old enchanting before applying new if equipped
item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, false);
itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0, m_caster->GetObjectGuid());
// add new enchanting if equipped
item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, true);
}
void Spell::EffectEnchantItemPrismatic(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (!itemTarget)
return;
Player* p_caster = (Player*)m_caster;
uint32 enchant_id = effect->EffectMiscValue;
if (!enchant_id)
return;
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if (!pEnchant)
return;
// support only enchantings with add socket in this slot
{
bool add_socket = false;
for (int i = 0; i < 3; ++i)
{
if (pEnchant->type[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
{
add_socket = true;
break;
}
}
if (!add_socket)
{
sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.",
m_spellInfo->Id, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC, ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
return;
}
}
// item can be in trade slot and have owner diff. from caster
Player* item_owner = itemTarget->GetOwner();
if (!item_owner)
return;
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
sLog.outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
p_caster->GetName(), p_caster->GetSession()->GetAccountId(),
itemTarget->GetProto()->Name1, itemTarget->GetEntry(),
item_owner->GetName(), item_owner->GetSession()->GetAccountId());
}
// remove old enchanting before applying new if equipped
item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, false);
itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0, m_caster->GetObjectGuid());
// add new enchanting if equipped
item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, true);
}
void Spell::EffectEnchantItemTmp(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* p_caster = (Player*)m_caster;
// Rockbiter Weapon
SpellClassOptionsEntry const* classOptions = m_spellInfo->GetSpellClassOptions();
if (classOptions && classOptions->SpellFamilyName == SPELLFAMILY_SHAMAN && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000400000))
{
uint32 spell_id = 0;
// enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value
// Note: damage calculated (correctly) with rounding int32(float(v)) but
// RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
switch (damage)
{
// Rank 1
case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
// Rank 2
case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4]
case 5: spell_id = 36751; break; // 20%
// Rank 3
case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6]
case 7: spell_id = 36755; break; // 20%
// Rank 4
case 9: spell_id = 36761; break; // 0% [ 7% == 6]
case 10: spell_id = 36758; break; // 14%
case 11: spell_id = 36760; break; // 20%
default:
sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW", damage);
return;
}
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
if (!spellInfo)
{
sLog.outError("Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id);
return;
}
Spell* spell = new Spell(m_caster, spellInfo, true);
SpellCastTargets targets;
targets.setItemTarget(itemTarget);
spell->SpellStart(&targets);
return;
}
if (!itemTarget)
return;
uint32 enchant_id = effect->EffectMiscValue;
if (!enchant_id)
{
sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,effect->EffectIndex);
return;
}
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if (!pEnchant)
{
sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have nonexistent enchanting id %u ",m_spellInfo->Id,effect->EffectIndex,enchant_id);
return;
}
// select enchantment duration
uint32 duration;
// rogue family enchantments exception by duration
if (m_spellInfo->Id == 38615)
duration = 1800; // 30 mins
// other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
else if(classOptions && classOptions->SpellFamilyName == SPELLFAMILY_ROGUE)
duration = 3600; // 1 hour
// shaman family enchantments
else if(classOptions && classOptions->SpellFamilyName == SPELLFAMILY_SHAMAN)
duration = 1800; // 30 mins
// other cases with this SpellVisual already selected
else if (m_spellInfo->SpellVisual[0] == 215)
duration = 1800; // 30 mins
// some fishing pole bonuses
else if (m_spellInfo->SpellVisual[0] == 563)
duration = 600; // 10 mins
// shaman rockbiter enchantments
else if (m_spellInfo->SpellVisual[0] == 0)
duration = 1800; // 30 mins
else if (m_spellInfo->Id == 29702)
duration = 300; // 5 mins
else if (m_spellInfo->Id == 37360)
duration = 300; // 5 mins
// default case
else
duration = 3600; // 1 hour
// item can be in trade slot and have owner diff. from caster
Player* item_owner = itemTarget->GetOwner();
if (!item_owner)
return;
if (item_owner != p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
{
sLog.outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
p_caster->GetName(), p_caster->GetSession()->GetAccountId(),
itemTarget->GetProto()->Name1, itemTarget->GetEntry(),
item_owner->GetName(), item_owner->GetSession()->GetAccountId());
}
// remove old enchanting before applying new if equipped
item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, false);
itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0, m_caster->GetObjectGuid());
// add new enchanting if equipped
item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true);
}
void Spell::EffectTameCreature(SpellEffectEntry const* /*effect*/)
{
// Caster must be player, checked in Spell::CheckCast
// Spell can be triggered, we need to check original caster prior to caster
Player* plr = (Player*)GetAffectiveCaster();
Creature* creatureTarget = (Creature*)unitTarget;
// cast finish successfully
// SendChannelUpdate(0);
finish();
Pet* pet = new Pet(HUNTER_PET);
if (!pet->CreateBaseAtCreature(creatureTarget))
{
delete pet;
return;
}
pet->SetOwnerGuid(plr->GetObjectGuid());
pet->SetCreatorGuid(plr->GetObjectGuid());
pet->setFaction(plr->getFaction());
pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
if (plr->IsPvP())
pet->SetPvP(true);
if (plr->IsFFAPvP())
pet->SetFFAPvP(true);
// level of hunter pet can't be less owner level at 5 levels
uint32 level = creatureTarget->getLevel() + 5 < plr->getLevel() ? (plr->getLevel() - 5) : creatureTarget->getLevel();
if (!pet->InitStatsForLevel(level))
{
sLog.outError("Pet::InitStatsForLevel() failed for creature (Entry: %u)!", creatureTarget->GetEntry());
delete pet;
return;
}
pet->GetCharmInfo()->SetPetNumber(sObjectMgr.GeneratePetNumber(), true);
// this enables pet details window (Shift+P)
pet->AIM_Initialize();
pet->InitPetCreateSpells();
pet->InitLevelupSpellsForLevel();
pet->InitTalentForLevel();
pet->SetHealth(pet->GetMaxHealth());
// "kill" original creature
creatureTarget->ForcedDespawn();
// prepare visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
// add to world
pet->GetMap()->Add((Creature*)pet);
// visual effect for levelup
pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
// caster have pet now
plr->SetPet(pet);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
plr->PetSpellInitialize();
}
void Spell::EffectSummonPet(SpellEffectEntry const* effect)
{
uint32 petentry = effect->EffectMiscValue;
Pet* NewSummon = new Pet;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
switch(m_caster->getClass())
{
case CLASS_HUNTER:
{
// Everything already taken care of, we are only here because we loaded pet from db successfully
delete NewSummon;
return;
}
default:
{
if (Pet* OldSummon = m_caster->GetPet())
OldSummon->Unsummon(PET_SAVE_NOT_IN_SLOT, m_caster);
// Load pet from db; if any to load
if (NewSummon->LoadPetFromDB((Player*)m_caster, petentry))
{
NewSummon->SetHealth(NewSummon->GetMaxHealth());
NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
return;
}
NewSummon->setPetType(SUMMON_PET);
}
}
}
else
NewSummon->setPetType(GUARDIAN_PET);
CreatureInfo const* cInfo = petentry ? ObjectMgr::GetCreatureTemplate(petentry) : nullptr;
if (!cInfo)
{
sLog.outErrorDb("EffectSummonPet: creature entry %u not found for spell %u.", petentry, m_spellInfo->Id);
delete NewSummon;
return;
}
CreatureCreatePos pos(m_caster, m_caster->GetOrientation());
Map* map = m_caster->GetMap();
uint32 pet_number = sObjectMgr.GeneratePetNumber();
if (!NewSummon->Create(map->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, pet_number))
{
delete NewSummon;
return;
}
NewSummon->SetRespawnCoord(pos);
// Level of pet summoned
uint32 level = std::max(m_caster->getLevel() + effect->EffectMultipleValue, 1.0f);
NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
NewSummon->SetOwnerGuid(m_caster->GetObjectGuid());
NewSummon->SetCreatorGuid(m_caster->GetObjectGuid());
NewSummon->setFaction(m_caster->getFaction());
NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(nullptr)));
NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
NewSummon->InitStatsForLevel(level);
NewSummon->InitPetCreateSpells();
NewSummon->InitLevelupSpellsForLevel();
NewSummon->InitTalentForLevel();
map->Add((Creature*)NewSummon);
NewSummon->AIM_Initialize();
m_caster->SetPet(NewSummon);
DEBUG_LOG("New Pet has guid %u", NewSummon->GetGUIDLow());
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SUPPORTABLE | UNIT_BYTE2_FLAG_AURAS);
NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
// generate new name for summon pet
NewSummon->SetName(sObjectMgr.GeneratePetName(petentry));
if (m_caster->IsPvP())
NewSummon->SetPvP(true);
if (m_caster->IsFFAPvP())
NewSummon->SetFFAPvP(true);
NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
((Player*)m_caster)->PetSpellInitialize();
}
else
{
// Notify Summoner
if (m_originalCaster && (m_originalCaster != m_caster)
&& (m_originalCaster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_originalCaster)->AI())
{
((Creature*)m_originalCaster)->AI()->JustSummoned(NewSummon);
if (m_originalCaster->IsInCombat() && !(NewSummon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)NewSummon)->AI()->AttackStart(m_originalCaster->getAttackerForHelper());
}
else if ((m_caster->GetTypeId() == TYPEID_UNIT) && ((Creature*)m_caster)->AI())
{
((Creature*)m_caster)->AI()->JustSummoned(NewSummon);
if (m_caster->IsInCombat() && !(NewSummon->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE)))
((Creature*)NewSummon)->AI()->AttackStart(m_caster->getAttackerForHelper());
}
}
}
void Spell::EffectLearnPetSpell(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* _player = (Player*)m_caster;
Pet* pet = _player->GetPet();
if (!pet)
return;
if (!pet->IsAlive())
return;
SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(effect->EffectTriggerSpell);
if(!learn_spellproto)
return;
pet->learnSpell(learn_spellproto->Id);
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
_player->PetSpellInitialize();
if (WorldObject const* caster = GetCastingObject())
DEBUG_LOG("Spell: %s has learned spell %u from %s", pet->GetGuidStr().c_str(), learn_spellproto->Id, caster->GetGuidStr().c_str());
}
void Spell::EffectTaunt(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
// this effect use before aura Taunt apply for prevent taunt already attacking target
// for spell as marked "non effective at already attacking target"
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
{
if (unitTarget->getVictim() == m_caster)
{
SendCastResult(SPELL_FAILED_DONT_REPORT);
return;
}
}
// Also use this effect to set the taunter's threat to the taunted creature's highest value
if (unitTarget->CanHaveThreatList() && unitTarget->GetThreatManager().getCurrentVictim())
unitTarget->GetThreatManager().addThreat(m_caster, unitTarget->GetThreatManager().getCurrentVictim()->getThreat());
}
void Spell::EffectWeaponDmg(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
// multiple weapon dmg effect workaround
// execute only the last weapon damage
// and handle all effects at once
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
switch(m_spellInfo->GetSpellEffectIdByIndex(SpellEffectIndex(j)))
{
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
if (j < int(effect->EffectIndex)) // we must calculate only at last weapon effect
return;
break;
}
}
// some spell specific modifiers
bool spellBonusNeedWeaponDamagePercentMod = false; // if set applied weapon damage percent mode to spell bonus
float weaponDamagePercentMod = 1.0f; // applied to weapon damage and to fixed effect damage bonus
float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
bool normalized = false;
int32 spell_bonus = 0; // bonus specific for spell
SpellClassOptionsEntry const* classOptions = m_spellInfo->GetSpellClassOptions();
switch(m_spellInfo->GetSpellFamilyName())
{
case SPELLFAMILY_GENERIC:
{
switch (m_spellInfo->Id)
{
// for spells with divided damage to targets
case 66765: case 66809: case 67331: // Meteor Fists
case 67333: // Meteor Fists
case 69055: // Bone Slice
case 71021: // Saber Lash
{
uint32 count = 0;
for(TargetList::const_iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
if(ihit->effectMask & (1<<effect->EffectIndex))
++count;
totalDamagePercentMod /= float(count); // divide to all targets
break;
}
}
break;
}
case SPELLFAMILY_WARRIOR:
{
// Devastate
if (m_spellInfo->SpellVisual[0] == 12295 && m_spellInfo->SpellIconID == 1508)
{
// Sunder Armor
Aura* sunder = unitTarget->GetAura(SPELL_AURA_MOD_RESISTANCE_PCT, SPELLFAMILY_WARRIOR, UI64LIT(0x0000000000004000), 0x00000000, m_caster->GetObjectGuid());
// Devastate bonus and sunder armor refresh
if (sunder)
{
sunder->GetHolder()->RefreshHolder();
spell_bonus += sunder->GetStackAmount() * CalculateDamage(EFFECT_INDEX_2, unitTarget);
}
// Devastate causing Sunder Armor Effect
// and no need to cast over max stack amount
if (!sunder || sunder->GetStackAmount() < sunder->GetSpellProto()->GetStackAmount())
m_caster->CastSpell(unitTarget, 58567, true);
}
break;
}
case SPELLFAMILY_ROGUE:
{
// Mutilate (for each hand)
if(classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x600000000))
{
bool found = false;
// fast check
if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
found = true;
// full aura scan
else
{
Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if(itr->second->GetSpellProto()->GetDispel() == DISPEL_POISON)
{
found = true;
break;
}
}
}
if (found)
totalDamagePercentMod *= 1.2f; // 120% if poisoned
}
// Fan of Knives
else if (m_caster->GetTypeId()==TYPEID_PLAYER && classOptions && (classOptions->SpellFamilyFlags & UI64LIT(0x0004000000000000)))
{
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType, true, true);
if (weapon && weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
totalDamagePercentMod *= 1.5f; // 150% to daggers
}
// Ghostly Strike
else if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->Id == 14278)
{
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType, true, true);
if (weapon && weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
totalDamagePercentMod *= 1.44f; // 144% to daggers
}
// Hemorrhage
else if (m_caster->GetTypeId() == TYPEID_PLAYER && classOptions && (classOptions->SpellFamilyFlags & UI64LIT(0x2000000)))
{
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType, true, true);
if (weapon && weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
totalDamagePercentMod *= 1.45f; // 145% to daggers
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Judgement of Command - receive benefit from Spell Damage and Attack Power
if(classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x00020000000000))
{
float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = m_caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(m_spellInfo));
if (holy < 0)
holy = 0;
spell_bonus += int32(ap * 0.08f) + int32(holy * 13 / 100);
}
break;
}
case SPELLFAMILY_HUNTER:
{
// Kill Shot
if (classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x80000000000000))
{
// 0.4*RAP added to damage (that is 0.2 if we apply PercentMod (200%) to spell_bonus, too)
spellBonusNeedWeaponDamagePercentMod = true;
spell_bonus += int32(0.2f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK));
}
break;
}
case SPELLFAMILY_SHAMAN:
{
// Skyshatter Harness item set bonus
// Stormstrike
if(classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x001000000000))
{
Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for (Unit::AuraList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr)
{
// Stormstrike AP Buff
if ((*citr)->GetModifier()->m_miscvalue == 5634)
{
m_caster->CastSpell(m_caster, 38430, true, NULL, *citr);
break;
}
}
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
// Blood Strike, Heart Strike, Obliterate
// Blood-Caked Strike
if (m_spellInfo->SpellIconID == 1736)
{
uint32 count = 0;
Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if(itr->second->GetSpellProto()->GetDispel() == DISPEL_DISEASE &&
itr->second->GetCasterGuid() == m_caster->GetObjectGuid())
++count;
}
if (count)
{
// Effect 1(for Blood-Caked Strike)/3(other) damage is bonus
float bonus = count * CalculateDamage(m_spellInfo->SpellIconID == 1736 ? EFFECT_INDEX_0 : EFFECT_INDEX_2, unitTarget) / 100.0f;
// Blood Strike, Blood-Caked Strike and Obliterate store bonus*2
if ((classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0002000000400000)) ||
m_spellInfo->SpellIconID == 1736)
bonus /= 2.0f;
totalDamagePercentMod *= 1.0f + bonus;
}
// Heart Strike secondary target
if (m_spellInfo->SpellIconID == 3145)
if (m_targets.getUnitTarget() != unitTarget)
weaponDamagePercentMod /= 2.0f;
}
// Glyph of Blood Strike
if( classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000400000) &&
m_caster->HasAura(59332) &&
unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
{
totalDamagePercentMod *= 1.2f; // 120% if snared
}
// Glyph of Death Strike
if( classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000010) &&
m_caster->HasAura(59336))
{
int32 rp = m_caster->GetPower(POWER_RUNIC_POWER) / 10;
if (rp > 25)
rp = 25;
totalDamagePercentMod *= 1.0f + rp / 100.0f;
}
// Glyph of Plague Strike
if( classOptions && classOptions->SpellFamilyFlags & UI64LIT(0x0000000000000001) &&
m_caster->HasAura(58657) )
{
totalDamagePercentMod *= 1.2f;
}
break;
}
}
int32 fixed_bonus = 0;
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* spellEffect = m_spellInfo->GetSpellEffect(SpellEffectIndex(j));
if(!spellEffect)
continue;
switch(spellEffect->Effect)
{
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
fixed_bonus += CalculateDamage(SpellEffectIndex(j), unitTarget);
break;
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
fixed_bonus += CalculateDamage(SpellEffectIndex(j), unitTarget);
normalized = true;
break;
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
weaponDamagePercentMod *= float(CalculateDamage(SpellEffectIndex(j), unitTarget)) / 100.0f;
// applied only to prev.effects fixed damage
fixed_bonus = int32(fixed_bonus * weaponDamagePercentMod);
break;
default:
break; // not weapon damage effect, just skip
}
}
// apply weaponDamagePercentMod to spell bonus also
if (spellBonusNeedWeaponDamagePercentMod)
spell_bonus = int32(spell_bonus * weaponDamagePercentMod);
// non-weapon damage
int32 bonus = spell_bonus + fixed_bonus;
// apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
if (bonus)
{
UnitMods unitMod;
switch (m_attackType)
{
default:
case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
}
float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
bonus = int32(bonus * weapon_total_pct);
}
// + weapon damage with applied weapon% dmg to base weapon damage in call
bonus += int32(m_caster->CalculateDamage(m_attackType, normalized) * weaponDamagePercentMod);
// total damage
bonus = int32(bonus * totalDamagePercentMod);
// prevent negative damage
m_damage += uint32(bonus > 0 ? bonus : 0);
// Hemorrhage
if (m_spellInfo->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x0000000002000000)))
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget, 1);
}
// Mangle (Cat): CP
else if (m_spellInfo->IsFitToFamily(SPELLFAMILY_DRUID, UI64LIT(0x0000040000000000)))
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget, 1);
}
}
void Spell::EffectThreat(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || !unitTarget->IsAlive() || !m_caster->IsAlive())
return;
if (!unitTarget->CanHaveThreatList())
return;
unitTarget->AddThreat(m_caster, float(damage), false, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
}
void Spell::EffectHealMaxHealth(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
uint32 heal = m_caster->GetMaxHealth();
m_healing += heal;
}
void Spell::EffectInterruptCast(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
if (!unitTarget->IsAlive())
return;
// TODO: not all spells that used this effect apply cooldown at school spells
// also exist case: apply cooldown to interrupted cast only and to all spells
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
{
if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i)))
{
SpellEntry const* curSpellInfo = spell->m_spellInfo;
// check if we can interrupt spell
if ((curSpellInfo->GetInterruptFlags() & SPELL_INTERRUPT_FLAG_INTERRUPT) && curSpellInfo->GetPreventionType() == SPELL_PREVENTION_TYPE_SILENCE )
{
unitTarget->ProhibitSpellSchool(GetSpellSchoolMask(curSpellInfo), GetSpellDuration(m_spellInfo));
unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
}
}
}
}
void Spell::EffectSummonObjectWild(SpellEffectEntry const* effect)
{
uint32 gameobject_id = effect->EffectMiscValue;
GameObject* pGameObj = new GameObject;
WorldObject* target = focusObject;
if (!target)
target = m_caster;
float x, y, z;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(x, y, z);
else
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
Map* map = target->GetMap();
if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
m_caster->GetPhaseMask(), x, y, z, target->GetOrientation()))
{
delete pGameObj;
return;
}
pGameObj->SetRespawnTime(m_duration > 0 ? m_duration / IN_MILLISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
// Wild object not have owner and check clickable by players
map->Add(pGameObj);
// Store the GO to the caster
m_caster->AddWildGameObject(pGameObj);
if (pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP && m_caster->GetTypeId() == TYPEID_PLAYER)
{
Player* pl = (Player*)m_caster;
BattleGround* bg = ((Player*)m_caster)->GetBattleGround();
switch (pGameObj->GetMapId())
{
case 489: // WS
{
if (bg && bg->GetTypeID() == BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
{
Team team = pl->GetTeam() == ALLIANCE ? HORDE : ALLIANCE;
((BattleGroundWS*)bg)->SetDroppedFlagGuid(pGameObj->GetObjectGuid(), team);
}
break;
}
case 566: // EY
{
if (bg && bg->GetTypeID() == BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
{
((BattleGroundEY*)bg)->SetDroppedFlagGuid(pGameObj->GetObjectGuid());
}
break;
}
}
}
pGameObj->SummonLinkedTrapIfAny();
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
((Creature*)m_caster)->AI()->JustSummoned(pGameObj);
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(pGameObj);
}
void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
{
// TODO: we must implement hunter pet summon at login there (spell 6962)
switch(m_spellInfo->GetSpellFamilyName())
{
case SPELLFAMILY_GENERIC:
{
switch (m_spellInfo->Id)
{
case 8856: // Bending Shinbone
{
if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spell_id = 0;
switch (urand(1, 5))
{
case 1: spell_id = 8854; break;
default: spell_id = 8855; break;
}
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
return;
}
case 17512: // Piccolo of the Flaming Fire
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
return;
}
case 20589: // Escape artist
{
if (!unitTarget)
return;
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
return;
}
case 22539: // Shadow Flame (All script effects, not just end ones to
case 22972: // prevent player from dodging the last triggered spell)
case 22975:
case 22976:
case 22977:
case 22978:
case 22979:
case 22980:
case 22981:
case 22982:
case 22983:
case 22984:
case 22985:
{
if (!unitTarget || !unitTarget->IsAlive())
return;
// Onyxia Scale Cloak
if (unitTarget->GetDummyAura(22683))
return;
// Shadow Flame
m_caster->CastSpell(unitTarget, 22682, true);
return;
}
case 24194: // Uther's Tribute
case 24195: // Grom's Tribute
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
uint8 race = m_caster->getRace();
uint32 spellId = 0;
switch (m_spellInfo->Id)
{
case 24194:
switch (race)
{
case RACE_HUMAN: spellId = 24105; break;
case RACE_DWARF: spellId = 24107; break;
case RACE_NIGHTELF: spellId = 24108; break;
case RACE_GNOME: spellId = 24106; break;
case RACE_DRAENEI: spellId = 69533; break;
}
break;
case 24195:
switch (race)
{
case RACE_ORC: spellId = 24104; break;
case RACE_UNDEAD: spellId = 24103; break;
case RACE_TAUREN: spellId = 24102; break;
case RACE_TROLL: spellId = 24101; break;
case RACE_BLOODELF: spellId = 69530; break;
}
break;
}
if (spellId)
m_caster->CastSpell(m_caster, spellId, true);
return;
}
case 24320: // Poisonous Blood
{
unitTarget->CastSpell(unitTarget, 24321, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 24324: // Blood Siphon
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(m_caster, unitTarget->HasAura(24321) ? 24323 : 24322, true);
return;
}
case 24590: // Brittle Armor - need remove one 24575 Brittle Armor aura
unitTarget->RemoveAuraHolderFromStack(24575);
return;
case 24714: // Trick
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (roll_chance_i(14)) // Trick (can be different critter models). 14% since below can have 1 of 6
m_caster->CastSpell(m_caster, 24753, true);
else // Random Costume, 6 different (plus add. for gender)
m_caster->CastSpell(m_caster, 24720, true);
return;
}
case 24717: // Pirate Costume
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Pirate Costume (male or female)
m_caster->CastSpell(unitTarget, unitTarget->getGender() == GENDER_MALE ? 24708 : 24709, true);
return;
}
case 24718: // Ninja Costume
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Ninja Costume (male or female)
m_caster->CastSpell(unitTarget, unitTarget->getGender() == GENDER_MALE ? 24711 : 24710, true);
return;
}
case 24719: // Leper Gnome Costume
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Leper Gnome Costume (male or female)
m_caster->CastSpell(unitTarget, unitTarget->getGender() == GENDER_MALE ? 24712 : 24713, true);
return;
}
case 24720: // Random Costume
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spellId = 0;
switch (urand(0, 6))
{
case 0:
spellId = unitTarget->getGender() == GENDER_MALE ? 24708 : 24709;
break;
case 1:
spellId = unitTarget->getGender() == GENDER_MALE ? 24711 : 24710;
break;
case 2:
spellId = unitTarget->getGender() == GENDER_MALE ? 24712 : 24713;
break;
case 3:
spellId = 24723;
break;
case 4:
spellId = 24732;
break;
case 5:
spellId = unitTarget->getGender() == GENDER_MALE ? 24735 : 24736;
break;
case 6:
spellId = 24740;
break;
}
m_caster->CastSpell(unitTarget, spellId, true);
return;
}
case 24737: // Ghost Costume
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Ghost Costume (male or female)
m_caster->CastSpell(unitTarget, unitTarget->getGender() == GENDER_MALE ? 24735 : 24736, true);
return;
}
case 24751: // Trick or Treat
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Tricked or Treated
unitTarget->CastSpell(unitTarget, 24755, true);
// Treat / Trick
unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 24714 : 24715, true);
return;
}
case 25140: // Orb teleport spells
case 25143:
case 25650:
case 25652:
case 29128:
case 29129:
case 35376:
case 35727:
{
if (!unitTarget)
return;
uint32 spellid;
switch (m_spellInfo->Id)
{
case 25140: spellid = 32568; break;
case 25143: spellid = 32572; break;
case 25650: spellid = 30140; break;
case 25652: spellid = 30141; break;
case 29128: spellid = 32571; break;
case 29129: spellid = 32569; break;
case 35376: spellid = 25649; break;
case 35727: spellid = 35730; break;
default:
return;
}
unitTarget->CastSpell(unitTarget, spellid, false);
return;
}
case 26004: // Mistletoe
{
if (!unitTarget)
return;
unitTarget->HandleEmote(EMOTE_ONESHOT_CHEER);
return;
}
case 26137: // Rotate Trigger
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, urand(0, 1) ? 26009 : 26136, true);
return;
}
case 26218: // Mistletoe
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spells[3] = {26206, 26207, 45036};
m_caster->CastSpell(unitTarget, spells[urand(0, 2)], true);
return;
}
case 26275: // PX-238 Winter Wondervolt TRAP
{
uint32 spells[4] = {26272, 26157, 26273, 26274};
// check presence
for (int j = 0; j < 4; ++j)
if (unitTarget->HasAura(spells[j], EFFECT_INDEX_0))
return;
// cast
unitTarget->CastSpell(unitTarget, spells[urand(0, 3)], true);
return;
}
case 26465: // Mercurial Shield - need remove one 26464 Mercurial Shield aura
unitTarget->RemoveAuraHolderFromStack(26464);
return;
case 26656: // Summon Black Qiraji Battle Tank
{
if (!unitTarget)
return;
// Prevent stacking of mounts
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
// Two separate mounts depending on area id (allows use both in and out of specific instance)
if (unitTarget->GetAreaId() == 3428)
unitTarget->CastSpell(unitTarget, 25863, false);
else
unitTarget->CastSpell(unitTarget, 26655, false);
return;
}
case 27687: // Summon Bone Minions
{
if (!unitTarget)
return;
// Spells 27690, 27691, 27692, 27693 are missing from DBC
// So we need to summon creature 16119 manually
float x, y, z;
float angle = unitTarget->GetOrientation();
for (uint8 i = 0; i < 4; ++i)
{
unitTarget->GetNearPoint(unitTarget, x, y, z, unitTarget->GetObjectBoundingRadius(), INTERACTION_DISTANCE, angle + i * M_PI_F / 2);
unitTarget->SummonCreature(16119, x, y, z, angle, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10 * MINUTE * IN_MILLISECONDS);
}
return;
}
case 27695: // Summon Bone Mages
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 27696, true);
unitTarget->CastSpell(unitTarget, 27697, true);
unitTarget->CastSpell(unitTarget, 27698, true);
unitTarget->CastSpell(unitTarget, 27699, true);
return;
}
case 28352: // Breath of Sargeras
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 28342, true);
return;
}
case 28374: // Decimate (Naxxramas: Gluth)
case 54426: // Decimate (Naxxramas: Gluth (spells are identical))
case 71123: // Decimate (ICC: Precious / Stinky)
{
if (!unitTarget)
return;
float downToHealthPercent = (m_spellInfo->Id != 71123 ? 5 : effect->CalculateSimpleValue()) * 0.01f;
int32 damage = unitTarget->GetHealth() - unitTarget->GetMaxHealth() * downToHealthPercent;
if (damage > 0)
m_caster->CastCustomSpell(unitTarget, 28375, &damage, nullptr, nullptr, true);
return;
}
case 28560: // Summon Blizzard
{
if (!unitTarget)
return;
m_caster->SummonCreature(16474, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000);
return;
}
case 28859: // Cleansing Flames
case 29126: // Cleansing Flames (Darnassus)
case 29135: // Cleansing Flames (Ironforge)
case 29136: // Cleansing Flames (Orgrimmar)
case 29137: // Cleansing Flames (Stormwind)
case 29138: // Cleansing Flames (Thunder Bluff)
case 29139: // Cleansing Flames (Undercity)
case 46671: // Cleansing Flames (Exodar)
case 46672: // Cleansing Flames (Silvermoon)
{
// Cleanse all magic, curse, disease and poison
if (!unitTarget)
return;
unitTarget->RemoveAurasWithDispelType(DISPEL_MAGIC);
unitTarget->RemoveAurasWithDispelType(DISPEL_CURSE);
unitTarget->RemoveAurasWithDispelType(DISPEL_DISEASE);
unitTarget->RemoveAurasWithDispelType(DISPEL_POISON);
return;
}
case 29395: // Break Kaliri Egg
{
uint32 creature_id = 0;
uint32 rand = urand(0, 99);
if (rand < 10)
creature_id = 17034;
else if (rand < 60)
creature_id = 17035;
else
creature_id = 17039;
if (WorldObject* pSource = GetAffectiveCasterObject())
pSource->SummonCreature(creature_id, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 120 * IN_MILLISECONDS);
return;
}
case 29830: // Mirren's Drinking Hat
{
uint32 item = 0;
switch (urand(1, 6))
{
case 1:
case 2:
case 3:
item = 23584; break; // Loch Modan Lager
case 4:
case 5:
item = 23585; break; // Stouthammer Lite
case 6:
item = 23586; break; // Aerie Peak Pale Ale
}
if (item)
DoCreateItem(effect,item);
break;
}
case 30541: // Blaze
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 30542, true);
break;
}
case 30469: // Nether Beam
{
if (!unitTarget)
return;
// The player and boss spells are different
if (unitTarget->GetTypeId() == TYPEID_PLAYER)
{
switch (m_caster->GetEntry())
{
case 17367:
if (unitTarget->HasAura(38638))
return;
m_caster->CastSpell(unitTarget, 30401, true);
m_caster->CastSpell(unitTarget, 30422, true);
break;
case 17368:
if (unitTarget->HasAura(38639))
return;
m_caster->CastSpell(unitTarget, 30402, true);
m_caster->CastSpell(unitTarget, 30423, true);
break;
case 17369:
if (unitTarget->HasAura(38637))
return;
m_caster->CastSpell(unitTarget, 30400, true);
m_caster->CastSpell(unitTarget, 30421, true);
break;
}
}
// target boss
else if (unitTarget->GetEntry() == 15689)
{
switch (m_caster->GetEntry())
{
case 17367:
m_caster->CastSpell(unitTarget, 30464, true);
m_caster->CastSpell(unitTarget, 30467, true);
break;
case 17368:
m_caster->CastSpell(unitTarget, 30463, true);
m_caster->CastSpell(unitTarget, 30468, true);
break;
case 17369:
m_caster->CastSpell(unitTarget, 30465, true);
m_caster->CastSpell(unitTarget, 30466, true);
break;
}
}
return;
}
case 30769: // Pick Red Riding Hood
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// cast Little Red Riding Hood
m_caster->CastSpell(unitTarget, 30768, true);
break;
}
case 30835: // Infernal Relay
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 30836, true, nullptr, nullptr, m_caster->GetObjectGuid());
break;
}
case 30918: // Improved Sprint
{
if (!unitTarget)
return;
// Removes snares and roots.
unitTarget->RemoveAurasAtMechanicImmunity(IMMUNE_TO_ROOT_AND_SNARE_MASK, 30918, true);
break;
}
case 37142: // Karazhan - Chess NPC Action: Melee Attack: Conjured Water Elemental
case 37143: // Karazhan - Chess NPC Action: Melee Attack: Charger
case 37147: // Karazhan - Chess NPC Action: Melee Attack: Human Cleric
case 37149: // Karazhan - Chess NPC Action: Melee Attack: Human Conjurer
case 37150: // Karazhan - Chess NPC Action: Melee Attack: King Llane
case 37220: // Karazhan - Chess NPC Action: Melee Attack: Summoned Daemon
case 32227: // Karazhan - Chess NPC Action: Melee Attack: Footman
case 32228: // Karazhan - Chess NPC Action: Melee Attack: Grunt
case 37337: // Karazhan - Chess NPC Action: Melee Attack: Orc Necrolyte
case 37339: // Karazhan - Chess NPC Action: Melee Attack: Orc Wolf
case 37345: // Karazhan - Chess NPC Action: Melee Attack: Orc Warlock
case 37348: // Karazhan - Chess NPC Action: Melee Attack: Warchief Blackhand
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 32247, true);
return;
}
case 32301: // Ping Shirrak
{
if (!unitTarget)
return;
// Cast Focus fire on caster
unitTarget->CastSpell(m_caster, 32300, true);
return;
}
case 33676: // Incite Chaos
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 33684, true);
return;
}
case 34653: // Fireball
case 36920: // Fireball (h)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, unitTarget->GetMap()->IsRegularDifficulty() ? 23971 : 30928, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 35865: // Summon Nether Vapor
{
if (!unitTarget)
return;
float x, y, z;
for (uint8 i = 0; i < 4; ++i)
{
m_caster->GetNearPoint(m_caster, x, y, z, 0.0f, INTERACTION_DISTANCE, M_PI_F * .5f * i + M_PI_F * .25f);
m_caster->SummonCreature(21002, x, y, z, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000);
}
return;
}
case 37431: // Spout
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, urand(0, 1) ? 37429 : 37430, true);
return;
}
case 37775: // Karazhan - Chess NPC Action - Poison Cloud
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 37469, true);
return;
}
case 37824: // Karazhan - Chess NPC Action - Shadow Mend
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 37456, true);
return;
}
case 38358: // Tidal Surge
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 38353, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 39338: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Horde
case 39342: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Alliance
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 39339, true);
return;
}
case 39341: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Horde
case 39344: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Alliance
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 41055: // Copy Weapon
case 63416: // Copy Weapon
case 69891: // Copy Weapon (No Threat)
{
if (m_caster->GetTypeId() != TYPEID_UNIT || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (Item* pItem = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
{
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, pItem->GetEntry());
// Unclear what this spell should do
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
}
return;
}
case 41072: // Bloodbolt
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 41126: // Flame Crash
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 41131, true);
break;
}
case 41213: // Throw Shield
case 43416: // Throw Shield
case 69222: // Throw Shield
case 73076: // Throw Shield
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 42281: // Sprouting
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(42280);
unitTarget->RemoveAurasDueToSpell(42294);
unitTarget->CastSpell(unitTarget, 42285, true);
unitTarget->CastSpell(unitTarget, 42291, true);
return;
}
case 42492: // Cast Energized
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 questId = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1);
if (!questId || !GetQuestTemplateStore(questId) || !((Player*)unitTarget)->IsCurrentQuest(questId))
return;
m_caster->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 42578: // Cannon Blast
{
if (!unitTarget)
return;
int32 basePoints = effect->CalculateSimpleValue();
unitTarget->CastCustomSpell(unitTarget, 42576, &basePoints, nullptr, nullptr, true);
return;
}
case 43365: // The Cleansing: Shrine Cast
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Script Effect Player Cast Mirror Image
m_caster->CastSpell(m_caster, 50217, true);
return;
}
case 43375: // Mixing Vrykul Blood
{
if (!unitTarget)
return;
uint32 triggeredSpell[] = {43376, 43378, 43970, 43377};
unitTarget->CastSpell(unitTarget, triggeredSpell[urand(0, 3)], true);
return;
}
case 44323: // Hawk Hunting
case 44407: // Hawk Hunting
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// check target entry specific to each spell
if (m_spellInfo->Id == 44323 && unitTarget->GetEntry() != 24746)
return;
if (m_spellInfo->Id == 44407 && unitTarget->GetEntry() != 24747)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
// despawn delay depends on the distance between caster and target
((Creature*)unitTarget)->ForcedDespawn(100 * unitTarget->GetDistance2d(m_caster));
return;
}
case 44364: // Rock Falcon Primer
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Are there anything special with this, a random chance or condition?
// Feeding Rock Falcon
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true, nullptr, nullptr, unitTarget->GetObjectGuid(), m_spellInfo);
return;
}
case 44455: // Character Script Effect Reverse Cast
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Creature* pTarget = (Creature*)unitTarget;
if (const SpellEntry *pSpell = sSpellStore.LookupEntry(effect->CalculateSimpleValue()))
{
// if we used item at least once...
if (pTarget->IsTemporarySummon() && int32(pTarget->GetEntry()) == pSpell->GetEffectMiscValue(SpellEffectIndex(effect->EffectIndex)))
{
TemporarySummon* pSummon = (TemporarySummon*)pTarget;
// can only affect "own" summoned
if (pSummon->GetSummonerGuid() == m_caster->GetObjectGuid())
{
if (pTarget->hasUnitState(UNIT_STAT_ROAMING | UNIT_STAT_ROAMING_MOVE))
pTarget->GetMotionMaster()->MovementExpired();
// trigger cast of quest complete script (see code for this spell below)
pTarget->CastSpell(pTarget, 44462, true);
pTarget->GetMotionMaster()->MovePoint(0, m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ());
}
return;
}
// or if it is first time used item, cast summon and despawn the target
m_caster->CastSpell(pTarget, pSpell, true);
pTarget->ForcedDespawn();
// TODO: here we should get pointer to the just summoned and make it move.
// without, it will be one extra use of quest item
}
return;
}
case 44462: // Cast Quest Complete on Master
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
Creature* pQuestCow = nullptr;
float range = 20.0f;
// search for a reef cow nearby
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, 24797, true, false, range);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pQuestCow, u_check);
Cell::VisitGridObjects(m_caster, searcher, range);
// no cows found, so return
if (!pQuestCow)
return;
if (!((Creature*)m_caster)->IsTemporarySummon())
return;
if (const SpellEntry *pSpell = sSpellStore.LookupEntry(effect->CalculateSimpleValue()))
{
TemporarySummon* pSummon = (TemporarySummon*)m_caster;
// all ok, so make summoner cast the quest complete
if (Unit* pSummoner = pSummon->GetSummoner())
pSummoner->CastSpell(pSummoner, pSpell, true);
}
return;
}
case 44876: // Force Cast - Portal Effect: Sunwell Isle
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 44870, true);
break;
}
case 44811: // Spectral Realm
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// If the player can't be teleported, send him a notification
if (unitTarget->HasAura(44867))
{
((Player*)unitTarget)->GetSession()->SendNotification(LANG_FAIL_ENTER_SPECTRAL_REALM);
return;
}
// Teleport target to the spectral realm, add debuff and force faction
unitTarget->CastSpell(unitTarget, 46019, true);
unitTarget->CastSpell(unitTarget, 46021, true);
unitTarget->CastSpell(unitTarget, 44845, true);
unitTarget->CastSpell(unitTarget, 44852, true);
return;
}
case 45141: // Burn
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 46394, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 45151: // Burn
{
if (!unitTarget || unitTarget->HasAura(46394))
return;
// Make the burn effect jump to another friendly target
unitTarget->CastSpell(unitTarget, 46394, true);
return;
}
case 45185: // Stomp
{
if (!unitTarget)
return;
// Remove the burn effect
unitTarget->RemoveAurasDueToSpell(46394);
return;
}
case 45204: // Clone Me!
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 45206: // Copy Off-hand Weapon
case 69892: // Copy Off-hand Weapon (No Threat)
{
if (m_caster->GetTypeId() != TYPEID_UNIT || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (Item* pItem = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
{
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, pItem->GetEntry());
// Unclear what this spell should do
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
}
return;
}
case 45235: // Blaze
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 45236, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 45260: // Karazhan - Chess - Force Player to Kill Bunny
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 45259, true);
return;
}
case 45313: // Anchor Here
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
((Creature*)unitTarget)->SetRespawnCoord(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetOrientation());
return;
}
case 45625: // Arcane Chains: Character Force Cast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (roll_chance_i(25)) // chance unknown, using 25
return;
static uint32 const spellPlayer[5] =
{
45674, // Bigger!
45675, // Shrunk
45678, // Yellow
45682, // Ghost
45684 // Polymorph
};
static uint32 const spellTarget[5] =
{
45673, // Bigger!
45672, // Shrunk
45677, // Yellow
45681, // Ghost
45683 // Polymorph
};
m_caster->CastSpell(m_caster, spellPlayer[urand(0, 4)], true);
unitTarget->CastSpell(unitTarget, spellTarget[urand(0, 4)], true);
return;
}
case 45691: // Magnataur On Death 1
{
// assuming caster is creature, if not, then return
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
Player* pPlayer = ((Creature*)m_caster)->GetOriginalLootRecipient();
if (!pPlayer)
return;
if (pPlayer->HasAura(45674) || pPlayer->HasAura(45675) || pPlayer->HasAura(45678) || pPlayer->HasAura(45682) || pPlayer->HasAura(45684))
pPlayer->CastSpell(pPlayer, 45686, true);
m_caster->CastSpell(m_caster, 45685, true);
return;
}
case 45713: // Naked Caravan Guard - Master Transform
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
const CreatureInfo* cTemplate = nullptr;
switch (m_caster->GetEntry())
{
case 25342: cTemplate = ObjectMgr::GetCreatureTemplate(25340); break;
case 25343: cTemplate = ObjectMgr::GetCreatureTemplate(25341); break;
}
if (!cTemplate)
return;
uint32 display_id = 0;
// Spell is designed to be used in creature addon.
// This makes it possible to set proper model before adding to map.
// For later, spell is used in gossip (with following despawn,
// so addon can reload the default model and data again).
// It should be noted that additional spell id's have been seen in relation to this spell, but
// those does not exist in client (45701 (regular spell), 45705-45712 (auras), 45459-45460 (auras)).
// We can assume 45705-45712 are transform auras, used instead of hard coded models in the below code.
// not in map yet OR no npc flags yet (restored after LoadCreatureAddon for respawn cases)
if (!m_caster->IsInMap(m_caster) || m_caster->GetUInt32Value(UNIT_NPC_FLAGS) == UNIT_NPC_FLAG_NONE)
{
display_id = Creature::ChooseDisplayId(cTemplate);
((Creature*)m_caster)->LoadEquipment(((Creature*)m_caster)->GetEquipmentId());
}
else
{
m_caster->SetUInt32Value(UNIT_NPC_FLAGS, cTemplate->NpcFlags);
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 0);
((Creature*)m_caster)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
switch (m_caster->GetDisplayId())
{
case 23246: display_id = 23245; break;
case 23247: display_id = 23250; break;
case 23248: display_id = 23251; break;
case 23249: display_id = 23252; break;
case 23124: display_id = 23253; break;
case 23125: display_id = 23254; break;
case 23126: display_id = 23255; break;
case 23127: display_id = 23256; break;
}
}
m_caster->SetDisplayId(display_id);
return;
}
case 45714: // Fog of Corruption (caster inform)
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 45717: // Fog of Corruption (player buff)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 45726, true);
return;
}
case 45785: // Sinister Reflection Clone
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 45833: // Power of the Blue Flight
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 45836, true);
return;
}
case 45892: // Sinister Reflection
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Summon 4 clones of the same player
for (uint8 i = 0; i < 4; ++i)
unitTarget->CastSpell(unitTarget, 45891, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 45918: // Soul Sever
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || !unitTarget->HasAura(45717))
return;
// kill all charmed targets
unitTarget->CastSpell(unitTarget, 45917, true);
return;
}
case 45958: // Signal Alliance
{
// "escort" aura not present, so let nothing happen
if (!m_caster->HasAura(effect->CalculateSimpleValue()))
return;
// "escort" aura is present so break; and let DB table dbscripts_on_spell be used and process further.
else
break;
}
case 46203: // Goblin Weather Machine
{
if (!unitTarget)
return;
uint32 spellId = 0;
switch (rand() % 4)
{
case 0: spellId = 46740; break;
case 1: spellId = 46739; break;
case 2: spellId = 46738; break;
case 3: spellId = 46736; break;
}
unitTarget->CastSpell(unitTarget, spellId, true);
break;
}
case 46289: // Negative Energy
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 46285, true);
return;
}
case 46430: // Synch Health
{
if (!unitTarget)
return;
unitTarget->SetHealth(m_caster->GetHealth());
return;
}
case 46642: // 5,000 Gold
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->ModifyMoney(5000 * GOLD);
break;
}
case 47097: // Surge Needle Teleporter
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (unitTarget->GetAreaId() == 4157)
unitTarget->CastSpell(unitTarget, 47324, true);
else if (unitTarget->GetAreaId() == 4156)
unitTarget->CastSpell(unitTarget, 47325, true);
break;
}
case 47311: // Quest - Jormungar Explosion Spell Spawner
{
// Summons npc's. They are expected to summon GO from 47315
// but there is no way to get the summoned, to trigger a spell
// cast (workaround can be done with ai script).
// Quest - Jormungar Explosion Summon Object
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 47309, true);
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 47924, true);
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 47925, true);
return;
}
case 47393: // The Focus on the Beach: Quest Completion Script
{
if (!unitTarget)
return;
// Ley Line Information
unitTarget->RemoveAurasDueToSpell(47391);
return;
}
case 47615: // Atop the Woodlands: Quest Completion Script
{
if (!unitTarget)
return;
// Ley Line Information
unitTarget->RemoveAurasDueToSpell(47473);
return;
}
case 47638: // The End of the Line: Quest Completion Script
{
if (!unitTarget)
return;
// Ley Line Information
unitTarget->RemoveAurasDueToSpell(47636);
return;
}
case 47703: // Unholy Union
{
m_caster->CastSpell(m_caster, 50254, true);
return;
}
case 47724: // Frost Draw
{
m_caster->CastSpell(m_caster, 50239, true);
return;
}
case 47958: // Crystal Spikes
case 57083: // Crystal Spikes (h2)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 47954, true);
unitTarget->CastSpell(unitTarget, 47955, true);
unitTarget->CastSpell(unitTarget, 47956, true);
unitTarget->CastSpell(unitTarget, 47957, true);
return;
}
case 48590: // Avenging Spirits
{
if (!unitTarget)
return;
// Summon 4 spirits summoners
unitTarget->CastSpell(unitTarget, 48586, true);
unitTarget->CastSpell(unitTarget, 48587, true);
unitTarget->CastSpell(unitTarget, 48588, true);
unitTarget->CastSpell(unitTarget, 48589, true);
return;
}
case 48603: // High Executor's Branding Iron
// Torture the Torturer: High Executor's Branding Iron Impact
unitTarget->CastSpell(unitTarget, 48614, true);
return;
case 48724: // The Denouncement: Commander Jordan On Death
case 48726: // The Denouncement: Lead Cannoneer Zierhut On Death
case 48728: // The Denouncement: Blacksmith Goodman On Death
case 48730: // The Denouncement: Stable Master Mercer On Death
{
// Compelled
if (!unitTarget || !m_caster->HasAura(48714))
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
// Gender spells
case 48762: // A Fall from Grace: Scarlet Raven Priest Image - Master
case 45759: // Warsong Orc Disguise
case 69672: // Sunreaver Disguise
case 69673: // Silver Covenant Disguise
{
if (!unitTarget)
return;
uint8 gender = unitTarget->getGender();
uint32 spellId;
switch (m_spellInfo->Id)
{
case 48762: spellId = (gender == GENDER_MALE ? 48763 : 48761); break;
case 45759: spellId = (gender == GENDER_MALE ? 45760 : 45762); break;
case 69672: spellId = (gender == GENDER_MALE ? 70974 : 70973); break;
case 69673: spellId = (gender == GENDER_MALE ? 70972 : 70971); break;
default: return;
}
unitTarget->CastSpell(unitTarget, spellId, true);
return;
}
case 48810: // Death's Door
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Spell effect order will summon creature first and then apply invisibility to caster.
// This result in that summoner/summoned can not see each other and that is not expected.
// Aura from 48814 can be used as a hack from creature_addon, but we can not get the
// summoned to cast this from this spell effect since we have no way to get pointer to creature.
// Most proper would be to summon to same visibility mask as summoner, and not use spell at all.
// Binding Life
m_caster->CastSpell(m_caster, 48809, true);
// After (after: meaning creature does not have auras at creation)
// creature is summoned and visible for player in map, it is expected to
// gain two auras. First from 29266(aura slot0) and then from 48808(aura slot1).
// We have no pointer to summoned, so only 48808 is possible from this spell effect.
// Binding Death
m_caster->CastSpell(m_caster, 48808, true);
return;
}
case 48811: // Despawn Forgotten Soul
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (!((Creature*)unitTarget)->IsTemporarySummon())
return;
TemporarySummon* pSummon = (TemporarySummon*)unitTarget;
Unit::AuraList const& images = unitTarget->GetAurasByType(SPELL_AURA_MIRROR_IMAGE);
if (images.empty())
return;
Unit* pCaster = images.front()->GetCaster();
Unit* pSummoner = unitTarget->GetMap()->GetUnit(pSummon->GetSummonerGuid());
if (pSummoner && pSummoner == pCaster)
pSummon->UnSummon();
return;
}
case 48917: // Who Are They: Cast from Questgiver
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Male Shadowy Disguise / Female Shadowy Disguise
unitTarget->CastSpell(unitTarget, unitTarget->getGender() == GENDER_MALE ? 38080 : 38081, true);
// Shadowy Disguise
unitTarget->CastSpell(unitTarget, 32756, true);
return;
}
case 49380: // Consume
case 59803: // Consume (heroic)
{
if (!unitTarget)
return;
// Each target hit buffs the caster
unitTarget->CastSpell(m_caster, m_spellInfo->Id == 49380 ? 49381 : 59805, true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 49405: // Invader Taunt Trigger
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 50217: // The Cleansing: Script Effect Player Cast Mirror Image
{
// Summon Your Inner Turmoil
m_caster->CastSpell(m_caster, 50167, true);
// Spell 50218 has TARGET_SCRIPT, but other wild summons near may exist, and then target can become wrong
// Only way to make this safe is to get the actual summoned by m_caster
// Your Inner Turmoil's Mirror Image Aura
m_caster->CastSpell(m_caster, 50218, true);
return;
}
case 50218: // The Cleansing: Your Inner Turmoil's Mirror Image Aura
{
if (!m_originalCaster || m_originalCaster->GetTypeId() != TYPEID_PLAYER || !unitTarget)
return;
// determine if and what weapons can be copied
switch(effect->EffectIndex)
{
case EFFECT_INDEX_1:
if (((Player*)m_originalCaster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
unitTarget->CastSpell(m_originalCaster, effect->CalculateSimpleValue(), true);
return;
case EFFECT_INDEX_2:
if (((Player*)m_originalCaster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
unitTarget->CastSpell(m_originalCaster, effect->CalculateSimpleValue(), true);
return;
default:
return;
}
return;
}
case 50238: // The Cleansing: Your Inner Turmoil's On Death Cast on Master
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
if (((Creature*)m_caster)->IsTemporarySummon())
{
TemporarySummon* pSummon = (TemporarySummon*)m_caster;
if (pSummon->GetSummonerGuid().IsPlayer())
{
if (Player* pSummoner = sObjectMgr.GetPlayer(pSummon->GetSummonerGuid()))
pSummoner->CastSpell(pSummoner, effect->CalculateSimpleValue(), true);
}
}
return;
}
case 50252: // Blood Draw
{
m_caster->CastSpell(m_caster, 50250, true);
return;
}
case 50255: // Poisoned Spear
case 59331: // Poisoned Spear (heroic)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true, nullptr, nullptr, m_originalCasterGUID);
return;
}
case 50439: // Script Cast Summon Image of Drakuru 05
{
// TODO: check if summon already exist, if it does in this instance, return.
// Summon Drakuru
m_caster->CastSpell(m_caster, 50446, true);
return;
}
case 50630: // Eject All Passengers
{
m_caster->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE);
return;
}
case 50725: // Vigilance - remove cooldown on Taunt
{
Unit* caster = GetAffectiveCaster();
if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)caster)->RemoveSpellCategoryCooldown(82, true);
return;
}
case 50742: // Ooze Combine
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
m_caster->CastSpell(unitTarget, 50747, true);
((Creature*)m_caster)->ForcedDespawn();
return;
}
case 50810: // Shatter
case 61546: // Shatter (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!unitTarget->HasAura(50812))
return;
unitTarget->RemoveAurasDueToSpell(50812);
unitTarget->CastSpell(unitTarget, m_spellInfo->Id == 50810 ? 50811 : 61547 , true, nullptr, nullptr, m_caster->GetObjectGuid());
return;
}
case 50894: // Zul'Drak Rat
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (SpellAuraHolder* pHolder = unitTarget->GetSpellAuraHolder(m_spellInfo->Id))
{
if (pHolder->GetStackAmount() + 1 >= m_spellInfo->GetStackAmount())
{
// Gluttonous Lurkers: Summon Gorged Lurking Basilisk
unitTarget->CastSpell(m_caster, 50928, true);
((Creature*)unitTarget)->ForcedDespawn(1);
}
}
return;
}
case 51519: // Death Knight Initiate Visual
{
if (!unitTarget)
return;
uint32 spellId = 0;
bool isMale = unitTarget->getGender() == GENDER_MALE;
switch (unitTarget->getRace())
{
case RACE_HUMAN: spellId = isMale ? 51520 : 51534; break;
case RACE_DWARF: spellId = isMale ? 51538 : 51537; break;
case RACE_NIGHTELF: spellId = isMale ? 51535 : 51536; break;
case RACE_GNOME: spellId = isMale ? 51539 : 51540; break;
case RACE_DRAENEI: spellId = isMale ? 51541 : 51542; break;
case RACE_ORC: spellId = isMale ? 51543 : 51544; break;
case RACE_UNDEAD: spellId = isMale ? 51549 : 51550; break;
case RACE_TAUREN: spellId = isMale ? 51547 : 51548; break;
case RACE_TROLL: spellId = isMale ? 51546 : 51545; break;
case RACE_BLOODELF: spellId = isMale ? 51551 : 51552; break;
default:
return;
}
unitTarget->CastSpell(unitTarget, spellId, true);
return;
}
case 51770: // Emblazon Runeblade
{
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
caster->CastSpell(caster, damage, false);
break;
}
case 51864: // Player Summon Nass
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// Summon Nass
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(51865))
{
// Only if he is not already there
if (!m_caster->FindGuardianWithEntry(pSpell->GetEffectMiscValue(EFFECT_INDEX_0)))
{
m_caster->CastSpell(m_caster, pSpell, true);
if (Pet* pPet = m_caster->FindGuardianWithEntry(pSpell->GetEffectMiscValue(EFFECT_INDEX_0)))
{
// Nass Periodic Say aura
pPet->CastSpell(pPet, 51868, true);
}
}
}
return;
}
case 51889: // Quest Accept Summon Nass
{
// This is clearly for quest accept, is spell 51864 then for gossip and does pretty much the same thing?
// Just "jumping" to what may be the "gossip-spell" for now, doing the same thing
m_caster->CastSpell(m_caster, 51864, true);
return;
}
case 51904: // Summon Ghouls On Scarlet Crusade
{
if (!unitTarget)
return;
// cast Summon Ghouls On Scarlet Crusade
float x, y, z;
m_targets.getDestination(x, y, z);
unitTarget->CastSpell(x, y, z, 54522, true, nullptr, nullptr, m_originalCasterGUID);
return;
}
case 51910: // Kickin' Nass: Quest Completion
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(51865))
{
// Is this all to be done at completion?
if (Pet* pPet = m_caster->FindGuardianWithEntry(pSpell->GetEffectMiscValue(EFFECT_INDEX_0)))
pPet->Unsummon(PET_SAVE_AS_DELETED, m_caster);
}
return;
}
case 52479: // Gift of the Harvester
{
if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget)
return;
// Each ghoul casts 52500 onto player, so use number of auras as check
Unit::SpellAuraHolderConstBounds bounds = m_caster->GetSpellAuraHolderBounds(52500);
uint32 summonedGhouls = std::distance(bounds.first, bounds.second);
m_caster->CastSpell(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), urand(0, 2) || summonedGhouls >= 5 ? 52505 : 52490, true);
return;
}
case 52555: // Dispel Scarlet Ghoul Credit Counter
{
if (!unitTarget)
return;
unitTarget->RemoveAurasByCasterSpell(effect->CalculateSimpleValue(), m_caster->GetObjectGuid());
return;
}
case 52694: // Recall Eye of Acherus
{
if (!m_caster || m_caster->GetTypeId() != TYPEID_UNIT)
return;
Unit* charmer = m_caster->GetCharmer();
if (!charmer || charmer->GetTypeId() != TYPEID_PLAYER)
return;
charmer->RemoveAurasDueToSpell(51923);
charmer->RemoveAurasDueToSpell(51852);
return;
}
case 52751: // Death Gate
{
if (!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
return;
// triggered spell is stored in m_spellInfo->EffectBasePoints[0]
unitTarget->CastSpell(unitTarget, damage, false);
break;
}
case 52941: // Song of Cleansing
{
uint32 spellId = 0;
switch (m_caster->GetAreaId())
{
case 4385: spellId = 52954; break; // Bittertide Lake
case 4290: spellId = 52958; break; // River's Heart
case 4388: spellId = 52959; break; // Wintergrasp River
}
if (spellId)
m_caster->CastSpell(m_caster, spellId, true);
break;
}
case 53110: // Devour Humanoid
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
((Creature*)unitTarget)->ForcedDespawn(8000);
return;
}
case 54182: // An End to the Suffering: Quest Completion Script
{
if (!unitTarget)
return;
// Remove aura (Mojo of Rhunok) given at quest accept / gossip
unitTarget->RemoveAurasDueToSpell(51967);
return;
}
case 54581: // Mammoth Explosion Spell Spawner
{
if (m_caster->GetTypeId() != TYPEID_UNIT)
return;
// Summons misc npc's. They are expected to summon GO from 54625
// but there is no way to get the summoned, to trigger a spell
// cast (workaround can be done with ai script).
// Quest - Mammoth Explosion Summon Object
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 54623, true);
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 54627, true);
for (int i = 0; i < 2; ++i)
m_caster->CastSpell(m_caster, 54628, true);
// Summon Main Mammoth Meat
m_caster->CastSpell(m_caster, 57444, true);
return;
}
case 54436: // Demonic Empowerment (succubus Vanish effect)
{
if (!unitTarget)
return;
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_STUN);
return;
}
case 55693: // Remove Collapsing Cave Aura
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
break;
}
case 56072: // Ride Red Dragon Buddy
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
break;
}
case 57082: // Crystal Spikes (h1)
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 57077, true);
unitTarget->CastSpell(unitTarget, 57078, true);
unitTarget->CastSpell(unitTarget, 57080, true);
unitTarget->CastSpell(unitTarget, 57081, true);
return;
}
case 57337: // Great Feast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 58067, true);
break;
}
case 57397: // Fish Feast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 45548, true);
unitTarget->CastSpell(unitTarget, 57073, true);
unitTarget->CastSpell(unitTarget, 57398, true);
break;
}
case 58466: // Gigantic Feast
case 58475: // Small Feast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 57085, true);
break;
}
case 58418: // Portal to Orgrimmar
case 58420: // Portal to Stormwind
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effect->EffectIndex != EFFECT_INDEX_0)
return;
uint32 spellID = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_0);
uint32 questID = m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1);
if (((Player*)unitTarget)->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !((Player*)unitTarget)->GetQuestRewardStatus(questID))
unitTarget->CastSpell(unitTarget, spellID, true);
return;
}
case 59317: // Teleporting
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// return from top
if (((Player*)unitTarget)->GetAreaId() == 4637)
unitTarget->CastSpell(unitTarget, 59316, true);
// teleport atop
else
unitTarget->CastSpell(unitTarget, 59314, true);
return;
} // random spell learn instead placeholder
case 59789: // Oracle Ablutions
{
if (!unitTarget)
return;
switch (unitTarget->GetPowerType())
{
case POWER_RUNIC_POWER:
{
unitTarget->CastSpell(unitTarget, 59812, true);
break;
}
case POWER_MANA:
{
int32 manapool = unitTarget->GetMaxPower(POWER_MANA) * 0.05;
unitTarget->CastCustomSpell(unitTarget, 59813, &manapool, nullptr, nullptr, true);
break;
}
case POWER_RAGE:
{
unitTarget->CastSpell(unitTarget, 59814, true);
break;
}
case POWER_ENERGY:
{
unitTarget->CastSpell(unitTarget, 59815, true);
break;
}
// These are not restored
case POWER_FOCUS:
case POWER_RUNE:
case POWER_HEALTH:
break;
}
return;
}
case 60893: // Northrend Alchemy Research
case 61177: // Northrend Inscription Research
case 61288: // Minor Inscription Research
case 61756: // Northrend Inscription Research (FAST QA VERSION)
case 64323: // Book of Glyph Mastery
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
// learn random explicit discovery recipe (if any)
if (uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, (Player*)m_caster))
((Player*)m_caster)->learnSpell(discoveredSpell, false);
return;
}
case 62042: // Stormhammer
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 62470, true);
unitTarget->CastSpell(m_caster, 64909, true);
return;
}
case 62217: // Unstable Energy
case 62922: // Unstable Energy (h)
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 62262: // Brightleaf Flux
{
if (!unitTarget)
return;
if (unitTarget->HasAura(62239))
unitTarget->RemoveAurasDueToSpell(62239);
else
{
uint32 stackAmount = urand(1, GetSpellStore()->LookupEntry(62239)->GetStackAmount());
for (uint8 i = 0; i < stackAmount; ++i)
unitTarget->CastSpell(unitTarget, 62239, true);
}
return;
}
case 62282: // Iron Roots
case 62440: // Strengthened Iron Roots
case 63598: // Iron Roots (h)
case 63601: // Strengthened Iron Roots (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || !((Creature*)unitTarget)->IsTemporarySummon())
return;
uint32 ownerAura = 0;
switch (m_spellInfo->Id)
{
case 62282: ownerAura = 62283; break;
case 62440: ownerAura = 62438; break;
case 63598: ownerAura = 62930; break;
case 63601: ownerAura = 62861; break;
};
if (Unit* summoner = unitTarget->GetMap()->GetUnit(((TemporarySummon*)unitTarget)->GetSummonerGuid()))
summoner->RemoveAurasDueToSpell(ownerAura);
return;
}
case 62381: // Chill
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(62373);
unitTarget->CastSpell(unitTarget, 62382, true);
return;
}
case 62488: // Activate Construct
{
if (!unitTarget || !unitTarget->HasAura(62468))
return;
unitTarget->RemoveAurasDueToSpell(62468);
unitTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
unitTarget->CastSpell(unitTarget, 64474, true);
if (m_caster->getVictim())
((Creature*)unitTarget)->AI()->AttackStart(m_caster->getVictim());
return;
}
case 62524: // Attuned to Nature 2 Dose Reduction
case 62525: // Attuned to Nature 10 Dose Reduction
case 62521: // Attuned to Nature 25 Dose Reduction
{
if (!unitTarget)
return;
uint32 numStacks = 0;
switch (m_spellInfo->Id)
{
case 62524: numStacks = 2; break;
case 62525: numStacks = 10; break;
case 62521: numStacks = 25; break;
};
uint32 spellId = effect->CalculateSimpleValue();
unitTarget->RemoveAuraHolderFromStack(spellId, numStacks);
return;
}
case 62552: // Defend
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 63119, true);
return;
}
case 62575: // Shield-Breaker (player)
case 68282: // Charge (player)
{
if (!unitTarget)
return;
unitTarget->RemoveAuraHolderFromStack(62719);
unitTarget->RemoveAuraHolderFromStack(64100);
unitTarget->RemoveAuraHolderFromStack(64192);
return;
}
case 62688: // Summon Wave - 10 Mob
{
uint32 spellId = effect->CalculateSimpleValue();
for (uint32 i = 0; i < 10; ++i)
m_caster->CastSpell(m_caster, spellId, true);
return;
}
case 62707: // Grab
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 62708, true);
return;
}
case 63010: // Charge
case 68307: // Charge
case 68504: // Shield-Breaker
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
Unit* owner = unitTarget->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!owner)
return;
owner->RemoveAuraHolderFromStack(62552);
owner->RemoveAuraHolderFromStack(63119);
if (owner->HasAura(63132))
{
owner->RemoveAurasDueToSpell(63132);
owner->CastSpell(unitTarget, 63131, true);
}
else if (owner->HasAura(63131))
{
owner->RemoveAurasDueToSpell(63131);
owner->CastSpell(unitTarget, 63130, true);
}
else if (owner->HasAura(63130))
owner->RemoveAurasDueToSpell(63130);
return;
}
case 63027: // Proximity Mines
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 15; ++i)
unitTarget->CastSpell(unitTarget, 65347, true);
return;
}
case 63119: // Block!
case 64192: // Block!
{
if (!unitTarget)
return;
if (unitTarget->HasAura(63132))
return;
else if (unitTarget->HasAura(63131))
{
unitTarget->RemoveAurasDueToSpell(63131);
unitTarget->CastSpell(unitTarget, 63132, true); // Shield Level 3
}
else if (unitTarget->HasAura(63130))
{
unitTarget->RemoveAurasDueToSpell(63130);
unitTarget->CastSpell(unitTarget, 63131, true); // Shield Level 2
}
else
unitTarget->CastSpell(unitTarget, 63130, true); // Shield Level 1
return;
}
case 63122: // Clear Insane
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 63633: // Summon Rubble
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 5; ++i)
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 63667: // Napalm Shell
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 63666 : 65026, true);
return;
}
case 63681: // Rocket Strike
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 63036, true);
return;
}
case 63795: // Psychosis
case 65301: // Psychosis (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
unitTarget->RemoveAuraHolderFromStack(63050, 12);
return;
}
case 63803: // Brain Link
case 64164: // Lunatic Gaze (Yogg)
case 64168: // Lunatic Gaze (Skull)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint8 removedAmount = 0;
switch (m_spellInfo->Id)
{
case 63803: removedAmount = 2; break;
case 64164: removedAmount = 4; break;
case 64168: removedAmount = 2; break;
}
unitTarget->RemoveAuraHolderFromStack(63050, removedAmount);
return;
}
case 63993: // Cancel Illusion Room Aura
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 63992, true);
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 64059: // Induce Madness
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || !unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
unitTarget->RemoveAurasDueToSpell(63050);
return;
}
case 64069: // Match Health (Rank 1)
{
if (!unitTarget)
return;
unitTarget->SetHealthPercent(m_caster->GetHealthPercent());
return;
}
case 64123: // Lunge
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, unitTarget->GetMap()->IsRegularDifficulty() ? 64125 : 64126, true);
return;
}
case 64131: // Lunge
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 64456: // Feral Essence Application Removal
{
if (!unitTarget)
return;
uint32 spellId = effect->CalculateSimpleValue();
unitTarget->RemoveAuraHolderFromStack(spellId);
return;
}
case 64466: // Empowering Shadows
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 64467: // Empowering Shadows
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 64468 : 64486, true);
return;
}
case 64475: // Strength of the Creator
{
if (!unitTarget)
return;
unitTarget->RemoveAuraHolderFromStack(64473);
return;
}
case 64623: // Frost Bomb
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 64627, true);
return;
}
case 64767: // Stormhammer
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (Creature* target = (Creature*)unitTarget)
{
target->AI()->EnterEvadeMode();
target->CastSpell(target, 62470, true);
target->CastSpell(m_caster, 64909, true);
target->CastSpell(target, 64778, true);
target->ForcedDespawn(10000);
}
return;
}
case 64841: // Rapid Burst
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 63382, false);
return;
}
case 65238: // Shattered Illusion
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 66477: // Bountiful Feast
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 65422, true);
unitTarget->CastSpell(unitTarget, 66622, true);
break;
}
case 66545: // Summon Memory
{
if (!unitTarget)
return;
uint32 memorySpells[25] = {66543, 66691, 66692, 66694, 66695, 66696, 66697, 66698, 66699, 66700, 66701,
66702, 66703, 66704, 66705, 66706, 66707, 66708, 66709, 66710, 66711, 66712, 66713, 66714, 66715
};
m_caster->CastSpell(unitTarget, memorySpells[urand(0, 24)], true);
return;
}
case 66741: // Chum the Water
{
// maybe this check should be done sooner?
if (!m_caster->IsInWater())
return;
uint32 spellId = 0;
// too low/high?
if (roll_chance_i(33))
spellId = 66737; // angry
else
{
switch (rand() % 3)
{
case 0: spellId = 66740; break; // blue
case 1: spellId = 66739; break; // tresher
case 2: spellId = 66738; break; // mako
}
}
if (spellId)
m_caster->CastSpell(m_caster, spellId, true);
return;
}
case 66744: // Make Player Destroy Totems
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Totem of the Earthen Ring does not really require or take reagents.
// Expecting RewardQuest() to already destroy them or we need additional code here to destroy.
unitTarget->CastSpell(unitTarget, 66747, true);
return;
}
case 67009: // Nether Power (ToC25: Lord Jaraxxus)
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 11; ++i)
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 67547: // Clear Val'kyr Essence
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(67590);
unitTarget->RemoveAurasDueToSpell(65684);
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 67590: // Powering Up
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (SpellAuraHolder* playerAura = unitTarget->GetSpellAuraHolder(m_spellInfo->Id))
{
if (playerAura && playerAura->GetStackAmount() == 100)
{
if (unitTarget->HasAuraOfDifficulty(65684))
unitTarget->CastSpell(unitTarget, 65724, true);
else if (unitTarget->HasAuraOfDifficulty(65686))
unitTarget->CastSpell(unitTarget, 65748, true);
unitTarget->RemoveAurasDueToSpell(m_spellInfo->Id);
}
}
return;
}
case 67751: // Ghoul Explode
{
if (!unitTarget)
return;
unitTarget->InterruptNonMeleeSpells(false);
unitTarget->CastSpell(unitTarget, 67729, false);
return;
}
case 68084: // Clear Val'kyr Touch of Light/Dark
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(66001);
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 68861: // Consume Soul (ICC FoS: Bronjahm)
if (unitTarget)
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
case 68871: // Wailing Souls
// Left or Right direction?
m_caster->CastSpell(m_caster, urand(0, 1) ? 68875 : 68876, false);
// Clear TargetGuid for sweeping
m_caster->SetTargetGuid(ObjectGuid());
return;
case 69048: // Mirrored Soul
{
if (!unitTarget)
return;
// This is extremely strange!
// The spell should send SMSG_CHANNEL_START, SMSG_SPELL_START
// However it has cast time 2s, but should send SMSG_SPELL_GO instantly.
m_caster->CastSpell(unitTarget, 69051, true);
return;
}
case 69051: // Mirrored Soul
{
if (!unitTarget)
return;
// Actually this spell should be sent with SMSG_SPELL_START
unitTarget->CastSpell(m_caster, 69023, true);
return;
}
case 69057: // Bone Spike Graveyard
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_1)))
return;
unitTarget->CastSpell(unitTarget, 69062, true);
return;
}
case 69140: // Coldflame (random target selection)
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 69147: // Coldflame
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 69195: // Pungent Blight
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 69298: // Cancel Resistant to Blight
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 69377: // Fortitude
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 72590, true);
return;
}
case 69378: // Blessing of Forgotten Kings
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 72586, true);
return;
}
case 69381: // Gift of the Wild
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 72588, true);
return;
}
case 69828: // Halls of Reflection Clone
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 71806: // Glittering Sparks
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 72034: // Whiteout
case 72096: // Whiteout (heroic)
{
// cast Whiteout visual
m_caster->CastSpell(unitTarget, 72036, true);
return;
}
case 72195: // Blood Link
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
uint32 auraStacks = 0;
if (SpellAuraHolder* playerAura = unitTarget->GetSpellAuraHolder(72371))
auraStacks = playerAura->GetStackAmount();
int32 missingStacks = unitTarget->GetPower(unitTarget->GetPowerType()) - auraStacks;
if (missingStacks <= 0)
return;
unitTarget->CastCustomSpell(unitTarget, 72371, &missingStacks, &missingStacks, nullptr, true);
return;
}
case 72219: // Gastric Bloat
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 auraStacks = 0;
if (SpellAuraHolder* playerAura = unitTarget->GetSpellAuraHolder(m_spellInfo->Id))
auraStacks = playerAura->GetStackAmount();
// cast Gastric Explosion on 10 stacks
if (auraStacks >= 10)
unitTarget->CastSpell(unitTarget, 72227, true, NULL, NULL, m_caster->GetObjectGuid());
return;
}
case 72257: // Remove Marks of the Fallen Champion
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 72409: // Rune of Blood
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 72705: // Coldflame (summon around the caster)
{
if (!unitTarget)
return;
// Cast summon spells 72701, 72702, 72703, 72704
for (uint32 triggeredSpell = effect->CalculateSimpleValue(); triggeredSpell < m_spellInfo->Id; ++triggeredSpell)
unitTarget->CastSpell(unitTarget, triggeredSpell, true);
return;
}
case 72900: // Start Halls of Reflection Quest AE
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (Player* target = (Player*)unitTarget)
target->CastSpell(target, target->GetTeam() == ALLIANCE ? 71351 : 71542, true);
return;
}
case 73142: // Bone Spike Graveyard (during storm)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->HasAura(69065))
return;
uint32 spellId = 0;
switch (urand(0, 2))
{
case 0: spellId = 69062; break;
case 1: spellId = 72669; break;
case 2: spellId = 72670; break;
}
unitTarget->CastSpell(unitTarget, spellId, true);
return;
}
case 74455: // Conflagration
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
}
break;
}
case SPELLFAMILY_WARLOCK:
{
switch (m_spellInfo->Id)
{
case 6201: // Healthstone creating spells
case 6202:
case 5699:
case 11729:
case 11730:
case 27230:
case 47871:
case 47878:
{
if (!unitTarget)
return;
uint32 itemtype;
uint32 rank = 0;
Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
{
if ((*i)->GetId() == 18692)
{
rank = 1;
break;
}
else if ((*i)->GetId() == 18693)
{
rank = 2;
break;
}
}
static uint32 const itypes[8][3] =
{
{ 5512, 19004, 19005}, // Minor Healthstone
{ 5511, 19006, 19007}, // Lesser Healthstone
{ 5509, 19008, 19009}, // Healthstone
{ 5510, 19010, 19011}, // Greater Healthstone
{ 9421, 19012, 19013}, // Major Healthstone
{22103, 22104, 22105}, // Master Healthstone
{36889, 36890, 36891}, // Demonic Healthstone
{36892, 36893, 36894} // Fel Healthstone
};
switch (m_spellInfo->Id)
{
case 6201:
itemtype = itypes[0][rank]; break; // Minor Healthstone
case 6202:
itemtype = itypes[1][rank]; break; // Lesser Healthstone
case 5699:
itemtype = itypes[2][rank]; break; // Healthstone
case 11729:
itemtype = itypes[3][rank]; break; // Greater Healthstone
case 11730:
itemtype = itypes[4][rank]; break; // Major Healthstone
case 27230:
itemtype = itypes[5][rank]; break; // Master Healthstone
case 47871:
itemtype = itypes[6][rank]; break; // Demonic Healthstone
case 47878:
itemtype = itypes[7][rank]; break; // Fel Healthstone
default:
return;
}
DoCreateItem( effect, itemtype );
return;
}
case 47193: // Demonic Empowerment
{
if (!unitTarget)
return;
uint32 entry = unitTarget->GetEntry();
uint32 spellID;
switch (entry)
{
case 416: spellID = 54444; break; // imp
case 417: spellID = 54509; break; // fellhunter
case 1860: spellID = 54443; break; // void
case 1863: spellID = 54435; break; // succubus
case 17252: spellID = 54508; break; // fellguard
default:
return;
}
unitTarget->CastSpell(unitTarget, spellID, true);
return;
}
case 47422: // Everlasting Affliction
{
// Need refresh caster corruption auras on target
Unit::SpellAuraHolderMap& suAuras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
{
SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
SpellClassOptionsEntry const* eaClassOptions = spellInfo->GetSpellClassOptions();
if(eaClassOptions && eaClassOptions->SpellFamilyName == SPELLFAMILY_WARLOCK &&
(eaClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000000002)) &&
(*itr).second->GetCasterGuid() == m_caster->GetObjectGuid())
(*itr).second->RefreshHolder();
}
return;
}
case 63521: // Guarded by The Light (Paladin spell with SPELLFAMILY_WARLOCK)
{
// Divine Plea, refresh on target (3 aura slots)
if (SpellAuraHolder* holder = unitTarget->GetSpellAuraHolder(54428))
holder->RefreshHolder();
return;
}
}
break;
}
case SPELLFAMILY_PRIEST:
{
switch (m_spellInfo->Id)
{
case 47948: // Pain and Suffering
{
if (!unitTarget)
return;
// Refresh Shadow Word: Pain on target
Unit::SpellAuraHolderMap& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
SpellClassOptionsEntry const* swpClassOptions = spellInfo->GetSpellClassOptions();
if (swpClassOptions && swpClassOptions->SpellFamilyName == SPELLFAMILY_PRIEST &&
(swpClassOptions->SpellFamilyFlags & UI64LIT(0x0000000000008000)) &&
(*itr).second->GetCasterGuid() == m_caster->GetObjectGuid())
{
(*itr).second->RefreshHolder();
return;
}
}
return;
}
default:
break;
}
break;
}
case SPELLFAMILY_HUNTER:
{
switch (m_spellInfo->Id)
{
case 53209: // Chimera Shot
{
if (!unitTarget)
return;
uint32 spellId = 0;
int32 basePoint = 0;
Unit* target = unitTarget;
Unit::SpellAuraHolderMap& Auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
{
SpellAuraHolder* holder = i->second;
if (holder->GetCasterGuid() != m_caster->GetObjectGuid())
continue;
// Search only Serpent Sting, Viper Sting, Scorpid Sting auras
SpellClassOptionsEntry const* stingClassOptions = holder->GetSpellProto()->GetSpellClassOptions();
if (!stingClassOptions || !stingClassOptions->SpellFamilyFlags.IsFitToFamilyMask(UI64LIT(0x000000800000C000)))
continue;
// Refresh aura duration
holder->RefreshHolder();
Aura* aura = holder->GetAuraByEffectIndex(EFFECT_INDEX_0);
if (!aura)
continue;
// Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
if (stingClassOptions->IsFitToFamilyMask(UI64LIT(0x0000000000004000)))
{
// m_amount already include RAP bonus
basePoint = aura->GetModifier()->m_amount * aura->GetAuraMaxTicks() * 40 / 100;
spellId = 53353; // Chimera Shot - Serpent
}
// Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
if (stingClassOptions->IsFitToFamilyMask(UI64LIT(0x0000008000000000)))
{
uint32 target_max_mana = unitTarget->GetMaxPower(POWER_MANA);
if (!target_max_mana)
continue;
// ignore non positive values (can be result apply spellmods to aura damage
uint32 pdamage = aura->GetModifier()->m_amount > 0 ? aura->GetModifier()->m_amount : 0;
// Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana)
uint32 maxmana = m_caster->GetMaxPower(POWER_MANA) * pdamage * 2 / 100;
pdamage = target_max_mana * pdamage / 100;
if (pdamage > maxmana)
pdamage = maxmana;
pdamage *= 4; // total aura damage
basePoint = pdamage * 60 / 100;
spellId = 53358; // Chimera Shot - Viper
target = m_caster;
}
// Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
if (stingClassOptions->IsFitToFamilyMask(UI64LIT(0x0000000000008000)))
spellId = 53359; // Chimera Shot - Scorpid
// ?? nothing say in spell desc (possibly need addition check)
// if ((familyFlag & UI64LIT(0x0000010000000000)) || // dot
// (familyFlag & UI64LIT(0x0000100000000000))) // stun
//{
// spellId = 53366; // 53366 Chimera Shot - Wyvern
//}
}
if (spellId)
m_caster->CastCustomSpell(target, spellId, &basePoint, 0, 0, false);
return;
}
case 53412: // Invigoration (pet triggered script, master targeted)
{
if (!unitTarget)
return;
Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
// Invigoration (master talent)
if ((*i)->GetModifier()->m_miscvalue == 8 && (*i)->GetSpellProto()->SpellIconID == 3487)
{
if (roll_chance_i((*i)->GetModifier()->m_amount))
{
unitTarget->CastSpell(unitTarget, 53398, true, nullptr, (*i), m_caster->GetObjectGuid());
break;
}
}
}
return;
}
case 53271: // Master's Call
{
if (!unitTarget)
return;
// script effect have in value, but this outdated removed part
unitTarget->CastSpell(unitTarget, 62305, true);
return;
}
default:
break;
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Judgement (seal trigger)
if (m_spellInfo->GetCategory() == SPELLCATEGORY_JUDGEMENT)
{
if (!unitTarget || !unitTarget->IsAlive())
return;
uint32 spellId1 = 0;
uint32 spellId2 = 0;
// Judgement self add switch
switch (m_spellInfo->Id)
{
case 53407: spellId1 = 20184; break; // Judgement of Justice
case 20271: // Judgement of Light
case 57774: spellId1 = 20185; break; // Judgement of Light
case 53408: spellId1 = 20186; break; // Judgement of Wisdom
default:
sLog.outError("Unsupported Judgement (seal trigger) spell (Id: %u) in Spell::EffectScriptEffect", m_spellInfo->Id);
return;
}
// offensive seals have aura dummy in 2 effect
Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
{
// search seal (offensive seals have judgement's aura dummy spell id in 2 effect
if ((*itr)->GetEffIndex() != EFFECT_INDEX_2 || !IsSealSpell((*itr)->GetSpellProto()))
continue;
spellId2 = (*itr)->GetModifier()->m_amount;
SpellEntry const* judge = sSpellStore.LookupEntry(spellId2);
if (!judge)
continue;
break;
}
// if there were no offensive seals than there is seal with proc trigger aura
if (!spellId2)
{
Unit::AuraList const& procTriggerAuras = m_caster->GetAurasByType(SPELL_AURA_PROC_TRIGGER_SPELL);
for (Unit::AuraList::const_iterator itr = procTriggerAuras.begin(); itr != procTriggerAuras.end(); ++itr)
{
if ((*itr)->GetEffIndex() != EFFECT_INDEX_0 || !IsSealSpell((*itr)->GetSpellProto()))
continue;
spellId2 = 54158;
break;
}
}
if (spellId1)
m_caster->CastSpell(unitTarget, spellId1, true);
if (spellId2)
m_caster->CastSpell(unitTarget, spellId2, true);
return;
}
break;
}
case SPELLFAMILY_POTION:
{
switch (m_spellInfo->Id)
{
case 28698: // Dreaming Glory
{
if (!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 28694, true);
break;
}
case 28702: // Netherbloom
{
if (!unitTarget)
return;
// 25% chance of casting a random buff
if (roll_chance_i(75))
return;
// triggered spells are 28703 to 28707
// Note: some sources say, that there was the possibility of
// receiving a debuff. However, this seems to be removed by a patch.
const uint32 spellid = 28703;
// don't overwrite an existing aura
for (uint8 i = 0; i < 5; ++i)
if (unitTarget->HasAura(spellid + i, EFFECT_INDEX_0))
return;
unitTarget->CastSpell(unitTarget, spellid + urand(0, 4), true);
break;
}
case 28720: // Nightmare Vine
{
if (!unitTarget)
return;
// 25% chance of casting Nightmare Pollen
if (roll_chance_i(75))
return;
unitTarget->CastSpell(unitTarget, 28721, true);
break;
}
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
switch (m_spellInfo->Id)
{
case 50842: // Pestilence
{
if (!unitTarget)
return;
Unit* mainTarget = m_targets.getUnitTarget();
if (!mainTarget)
return;
// do only refresh diseases on main target if caster has Glyph of Disease
if (mainTarget == unitTarget && !m_caster->HasAura(63334))
return;
// Blood Plague
if (mainTarget->HasAura(55078))
m_caster->CastSpell(unitTarget, 55078, true);
// Frost Fever
if (mainTarget->HasAura(55095))
m_caster->CastSpell(unitTarget, 55095, true);
break;
}
}
break;
}
}
// normal DB scripted effect
if (!unitTarget)
return;
// Script based implementation. Must be used only for not good for implementation in core spell effects
// So called only for not processed cases
if (unitTarget->GetTypeId() == TYPEID_UNIT)
{
if (sScriptMgr.OnEffectScriptEffect(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget, m_originalCasterGUID))
return;
}
// Previous effect might have started script
if (!ScriptMgr::CanSpellEffectStartDBScript(m_spellInfo, SpellEffectIndex(effect->EffectIndex)))
return;
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell ScriptStart spellid %u in EffectScriptEffect", m_spellInfo->Id);
m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
void Spell::EffectSanctuary(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
// unitTarget->CombatStop();
unitTarget->CombatStop();
unitTarget->getHostileRefManager().deleteReferences(); // stop all fighting
// Vanish allows to remove all threat and cast regular stealth so other spells can be used
if (m_spellInfo->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x0000000000000800)))
((Player*)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
}
void Spell::EffectAddComboPoints(SpellEffectEntry const* effect /*effect*/)
{
if (!unitTarget)
return;
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
if (damage <= 0)
return;
((Player*)m_caster)->AddComboPoints(unitTarget, damage);
}
void Spell::EffectDuel(SpellEffectEntry const* effect)
{
if (!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* caster = (Player*)m_caster;
Player* target = (Player*)unitTarget;
// caster or target already have requested duel
if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetObjectGuid()))
return;
// Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId());
if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_DUEL))
{
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
return;
}
AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId());
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_DUEL))
{
SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
return;
}
// CREATE DUEL FLAG OBJECT
GameObject* pGameObj = new GameObject;
uint32 gameobject_id = effect->EffectMiscValue;
Map* map = m_caster->GetMap();
float x = (m_caster->GetPositionX() + unitTarget->GetPositionX()) * 0.5f;
float y = (m_caster->GetPositionY() + unitTarget->GetPositionY()) * 0.5f;
float z = m_caster->GetPositionZ();
m_caster->UpdateAllowedPositionZ(x, y, z);
if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation()))
{
delete pGameObj;
return;
}
pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction());
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() + 1);
pGameObj->SetRespawnTime(m_duration > 0 ? m_duration / IN_MILLISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
map->Add(pGameObj);
// END
// Send request
WorldPacket data(SMSG_DUEL_REQUESTED, 8 + 8);
data << pGameObj->GetObjectGuid();
data << caster->GetObjectGuid();
caster->GetSession()->SendPacket(&data);
target->GetSession()->SendPacket(&data);
// create duel-info
DuelInfo* duel = new DuelInfo;
duel->initiator = caster;
duel->opponent = target;
duel->startTime = 0;
duel->startTimer = 0;
caster->duel = duel;
DuelInfo* duel2 = new DuelInfo;
duel2->initiator = caster;
duel2->opponent = caster;
duel2->startTime = 0;
duel2->startTimer = 0;
target->duel = duel2;
caster->SetGuidValue(PLAYER_DUEL_ARBITER, pGameObj->GetObjectGuid());
target->SetGuidValue(PLAYER_DUEL_ARBITER, pGameObj->GetObjectGuid());
}
void Spell::EffectStuck(SpellEffectEntry const* effect /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!sWorld.getConfig(CONFIG_BOOL_CAST_UNSTUCK))
return;
Player* pTarget = (Player*)unitTarget;
DEBUG_LOG("Spell Effect: Stuck");
DETAIL_LOG("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ());
if (pTarget->IsTaxiFlying())
return;
// homebind location is loaded always
pTarget->TeleportToHomebind(unitTarget == m_caster ? TELE_TO_SPELL : 0);
// Stuck spell trigger Hearthstone cooldown
SpellEntry const* spellInfo = sSpellStore.LookupEntry(8690);
if (!spellInfo)
return;
Spell spell(pTarget, spellInfo, true);
spell.SendSpellCooldown();
}
void Spell::EffectSummonPlayer(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Evil Twin (ignore player summon, but hide this for summoner)
if (unitTarget->GetDummyAura(23445))
return;
float x, y, z;
m_caster->GetClosePoint(x, y, z, unitTarget->GetObjectBoundingRadius());
((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(), x, y, z);
WorldPacket data(SMSG_SUMMON_REQUEST, 8 + 4 + 4);
data << m_caster->GetObjectGuid(); // summoner guid
data << uint32(m_caster->GetZoneId()); // summoner zone
data << uint32(MAX_PLAYER_SUMMON_DELAY * IN_MILLISECONDS); // auto decline after msecs
((Player*)unitTarget)->GetSession()->SendPacket(&data);
}
static ScriptInfo generateActivateCommand()
{
ScriptInfo si;
si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
si.id = 0;
si.buddyEntry = 0;
si.searchRadiusOrGuid = 0;
si.data_flags = 0x00;
return si;
}
void Spell::EffectActivateObject(SpellEffectEntry const* effect)
{
if (!gameObjTarget)
return;
uint32 misc_value = uint32(effect->EffectMiscValue);
switch (misc_value)
{
case 1: // GO simple use
case 2: // unk - 2 spells
case 4: // unk - 1 spell
case 5: // GO trap usage
case 7: // unk - 2 spells
case 8: // GO usage with TargetB = none or random
case 10: // GO explosions
case 11: // unk - 1 spell
case 19: // unk - 1 spell
case 20: // unk - 2 spells
{
static ScriptInfo activateCommand = generateActivateCommand();
int32 delay_secs = effect->CalculateSimpleValue();
gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
break;
}
case 3: // GO custom anim - found mostly in Lunar Fireworks spells
gameObjTarget->SendGameObjectCustomAnim(gameObjTarget->GetObjectGuid());
break;
case 12: // GO state active alternative - found mostly in Simon Game spells
gameObjTarget->UseDoorOrButton(0, true);
break;
case 13: // GO state ready - found only in Simon Game spells
gameObjTarget->ResetDoorOrButton();
break;
case 15: // GO destroy
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
case 16: // GO custom use - found mostly in Wind Stones spells, Simon Game spells and other GO target summoning spells
{
switch (m_spellInfo->Id)
{
case 24734: // Summon Templar Random
case 24744: // Summon Templar (fire)
case 24756: // Summon Templar (air)
case 24758: // Summon Templar (earth)
case 24760: // Summon Templar (water)
case 24763: // Summon Duke Random
case 24765: // Summon Duke (fire)
case 24768: // Summon Duke (air)
case 24770: // Summon Duke (earth)
case 24772: // Summon Duke (water)
case 24784: // Summon Royal Random
case 24786: // Summon Royal (fire)
case 24788: // Summon Royal (air)
case 24789: // Summon Royal (earth)
case 24790: // Summon Royal (water)
{
uint32 npcEntry = 0;
uint32 templars[] = {15209, 15211, 15212, 15307};
uint32 dukes[] = {15206, 15207, 15208, 15220};
uint32 royals[] = {15203, 15204, 15205, 15305};
switch (m_spellInfo->Id)
{
case 24734: npcEntry = templars[urand(0, 3)]; break;
case 24763: npcEntry = dukes[urand(0, 3)]; break;
case 24784: npcEntry = royals[urand(0, 3)]; break;
case 24744: npcEntry = 15209; break;
case 24756: npcEntry = 15212; break;
case 24758: npcEntry = 15307; break;
case 24760: npcEntry = 15211; break;
case 24765: npcEntry = 15206; break;
case 24768: npcEntry = 15220; break;
case 24770: npcEntry = 15208; break;
case 24772: npcEntry = 15207; break;
case 24786: npcEntry = 15203; break;
case 24788: npcEntry = 15204; break;
case 24789: npcEntry = 15205; break;
case 24790: npcEntry = 15305; break;
}
gameObjTarget->SummonCreature(npcEntry, gameObjTarget->GetPositionX(), gameObjTarget->GetPositionY(), gameObjTarget->GetPositionZ(), gameObjTarget->GetAngle(m_caster), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
}
case 40176: // Simon Game pre-game Begin, blue
case 40177: // Simon Game pre-game Begin, green
case 40178: // Simon Game pre-game Begin, red
case 40179: // Simon Game pre-game Begin, yellow
case 40283: // Simon Game END, blue
case 40284: // Simon Game END, green
case 40285: // Simon Game END, red
case 40286: // Simon Game END, yellow
case 40494: // Simon Game, switched ON
case 40495: // Simon Game, switched OFF
case 40512: // Simon Game, switch...disable Off switch
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
break;
case 40632: // Summon Gezzarak the Huntress
case 40640: // Summon Karrog
case 40642: // Summon Darkscreecher Akkarai
case 40644: // Summon Vakkiz the Windrager
case 41004: // Summon Terokk
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
case 46085: // Place Fake Fur
{
float x, y, z;
gameObjTarget->GetClosePoint(x, y, z, gameObjTarget->GetObjectBoundingRadius(), 2 * INTERACTION_DISTANCE, frand(0, M_PI_F * 2));
// Note: event script is implemented in script library
gameObjTarget->SummonCreature(25835, x, y, z, gameObjTarget->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15000);
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
break;
}
case 46592: // Summon Ahune Lieutenant
{
uint32 npcEntry = 0;
switch (gameObjTarget->GetEntry())
{
case 188049: npcEntry = 26116; break; // Frostwave Lieutenant (Ashenvale)
case 188137: npcEntry = 26178; break; // Hailstone Lieutenant (Desolace)
case 188138: npcEntry = 26204; break; // Chillwind Lieutenant (Stranglethorn)
case 188148: npcEntry = 26214; break; // Frigid Lieutenant (Searing Gorge)
case 188149: npcEntry = 26215; break; // Glacial Lieutenant (Silithus)
case 188150: npcEntry = 26216; break; // Glacial Templar (Hellfire Peninsula)
}
gameObjTarget->SummonCreature(npcEntry, gameObjTarget->GetPositionX(), gameObjTarget->GetPositionY(), gameObjTarget->GetPositionZ(), gameObjTarget->GetAngle(m_caster), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
}
}
break;
}
case 17: // GO unlock - found mostly in Simon Game spells
gameObjTarget->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
break;
default:
sLog.outError("Spell::EffectActivateObject called with unknown misc value. Spell Id %u", m_spellInfo->Id);
break;
}
}
void Spell::EffectApplyGlyph(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)m_caster;
// glyph sockets level requirement
uint8 minLevel = 0;
switch (m_glyphIndex)
{
case 0:
case 1:
case 6: minLevel = 25; break;
case 2:
case 3:
case 7: minLevel = 50; break;
case 4:
case 5:
case 8: minLevel = 75; break;
}
if (minLevel && m_caster->getLevel() < minLevel)
{
SendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED);
return;
}
// apply new one
if(uint32 glyph = effect->EffectMiscValue)
{
if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph))
{
if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
{
if (gp->TypeFlags != gs->TypeFlags)
{
SendCastResult(SPELL_FAILED_INVALID_GLYPH);
return; // glyph slot mismatch
}
}
// remove old glyph
player->ApplyGlyph(m_glyphIndex, false);
player->SetGlyph(m_glyphIndex, glyph);
player->ApplyGlyph(m_glyphIndex, true);
player->SendTalentsInfoData(false);
}
}
}
void Spell::EffectEnchantHeldItem(SpellEffectEntry const* effect)
{
// this is only item spell effect applied to main-hand weapon of target player (players in area)
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* item_owner = (Player*)unitTarget;
Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
if (!item)
return;
// must be equipped
if (!item ->IsEquipped())
return;
if (effect->EffectMiscValue)
{
uint32 enchant_id = effect->EffectMiscValue;
int32 duration = m_duration; // Try duration index first...
if (!duration)
duration = m_currentBasePoints[SpellEffectIndex(effect->EffectIndex)]; // Base points after...
if (!duration)
duration = 10; // 10 seconds for enchants which don't have listed duration
SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
if (!pEnchant)
return;
// Always go to temp enchantment slot
EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
// Enchantment will not be applied if a different one already exists
if (item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
return;
// Apply the temporary enchantment
item->SetEnchantment(slot, enchant_id, duration * IN_MILLISECONDS, 0, m_caster->GetObjectGuid());
item_owner->ApplyEnchantment(item, slot, true);
}
}
void Spell::EffectDisEnchant(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* p_caster = (Player*)m_caster;
if (!itemTarget || !itemTarget->GetProto()->DisenchantID)
return;
p_caster->UpdateCraftSkill(m_spellInfo->Id);
((Player*)m_caster)->SendLoot(itemTarget->GetObjectGuid(), LOOT_DISENCHANTING);
// item will be removed at disenchanting end
}
void Spell::EffectInebriate(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)unitTarget;
uint8 drunkValue = player->GetDrunkValue() + (uint8)damage;
if (drunkValue > 100)
{
drunkValue = 100;
if (roll_chance_i(25))
player->CastSpell(player, 67468, false); // Drunken Vomit
}
player->SetDrunkValue(drunkValue, m_CastItem ? m_CastItem->GetEntry() : 0);
}
void Spell::EffectFeedPet(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* _player = (Player*)m_caster;
Item* foodItem = m_targets.getItemTarget();
if (!foodItem)
return;
Pet* pet = _player->GetPet();
if (!pet)
return;
if (!pet->IsAlive())
return;
int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
if (benefit <= 0)
return;
uint32 count = 1;
_player->DestroyItemCount(foodItem, count, true);
// TODO: fix crash when a spell has two effects, both pointed at the same item target
m_caster->CastCustomSpell(pet, effect->EffectTriggerSpell, &benefit, NULL, NULL, true);
}
void Spell::EffectDismissPet(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Pet* pet = m_caster->GetPet();
// not let dismiss dead pet
if (!pet || !pet->IsAlive())
return;
pet->Unsummon(PET_SAVE_NOT_IN_SLOT, m_caster);
}
void Spell::EffectSummonObject(SpellEffectEntry const* effect)
{
uint32 go_id = effect->EffectMiscValue;
uint8 slot = effect->EffectMiscValueB;
if (slot >= MAX_OBJECT_SLOT)
return;
if (ObjectGuid guid = m_caster->m_ObjectSlotGuid[slot])
{
if (GameObject* obj = m_caster ? m_caster->GetMap()->GetGameObject(guid) : NULL)
obj->SetLootState(GO_JUST_DEACTIVATED);
m_caster->m_ObjectSlotGuid[slot].Clear();
}
GameObject* pGameObj = new GameObject;
float x, y, z;
// If dest location if present
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(x, y, z);
// Summon in random point all other units if location present
else
m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
Map* map = m_caster->GetMap();
if (!pGameObj->Create(map->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation()))
{
delete pGameObj;
return;
}
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
pGameObj->SetRespawnTime(m_duration > 0 ? m_duration / IN_MILLISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
map->Add(pGameObj);
m_caster->m_ObjectSlotGuid[slot] = pGameObj->GetObjectGuid();
pGameObj->SummonLinkedTrapIfAny();
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
((Creature*)m_caster)->AI()->JustSummoned(pGameObj);
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(pGameObj);
}
void Spell::EffectResurrect(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (unitTarget->IsAlive() || !unitTarget->IsInWorld())
return;
switch (m_spellInfo->Id)
{
case 8342: // Defibrillate (Goblin Jumper Cables) has 33% chance on success
case 22999: // Defibrillate (Goblin Jumper Cables XL) has 50% chance on success
case 54732: // Defibrillate (Gnomish Army Knife) has 67% chance on success
{
uint32 failChance = 0;
uint32 failSpellId = 0;
switch (m_spellInfo->Id)
{
case 8342: failChance = 67; failSpellId = 8338; break;
case 22999: failChance = 50; failSpellId = 23055; break;
case 54732: failChance = 33; failSpellId = 0; break;
}
if (roll_chance_i(failChance))
{
if (failSpellId)
m_caster->CastSpell(m_caster, failSpellId, true, m_CastItem);
return;
}
break;
}
default:
break;
}
Player* pTarget = ((Player*)unitTarget);
if (pTarget->isRessurectRequested()) // already have one active request
return;
uint32 health = pTarget->GetMaxHealth() * damage / 100;
uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
pTarget->setResurrectRequestData(m_caster->GetObjectGuid(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
SendResurrectRequest(pTarget);
}
void Spell::EffectAddExtraAttacks(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || !unitTarget->IsAlive())
return;
if (unitTarget->m_extraAttacks)
return;
unitTarget->m_extraAttacks = damage;
}
void Spell::EffectParry(SpellEffectEntry const* /*effect*/)
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->SetCanParry(true);
}
void Spell::EffectBlock(SpellEffectEntry const* /*effect*/)
{
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
((Player*)unitTarget)->SetCanBlock(true);
}
void Spell::EffectLeapForward(SpellEffectEntry const* effect)
{
float dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->rangeIndex));
const float IN_OR_UNDER_LIQUID_RANGE = 0.8f; // range to make player under liquid or on liquid surface from liquid level
G3D::Vector3 prevPos, nextPos;
float orientation = unitTarget->GetOrientation();
prevPos.x = unitTarget->GetPositionX();
prevPos.y = unitTarget->GetPositionY();
prevPos.z = unitTarget->GetPositionZ();
float groundZ = prevPos.z;
// falling case
if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), prevPos.x, prevPos.y, groundZ, 3.0f) && unitTarget->m_movementInfo.HasMovementFlag(MOVEFLAG_FALLING))
{
nextPos.x = prevPos.x + dist * cos(orientation);
nextPos.y = prevPos.y + dist * sin(orientation);
nextPos.z = prevPos.z - 2.0f; // little hack to avoid the impression to go up when teleporting instead of continue to fall. This value may need some tweak
//
GridMapLiquidData liquidData;
if (unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
{
if (fabs(nextPos.z - liquidData.level) < 10.0f)
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE;
}
else
{
// fix z to ground if near of it
unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z, 10.0f);
}
// check any obstacle and fix coords
unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 0.5f, nextPos.x, nextPos.y, nextPos.z, unitTarget->GetPhaseMask(), -0.5f);
// teleport
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
//sLog.outString("Falling BLINK!");
return;
}
// fix origin position if player was jumping and near of the ground but not in ground
if (fabs(prevPos.z - groundZ) > 0.5f)
prevPos.z = groundZ;
//check if in liquid
bool isPrevInLiquid = unitTarget->GetMap()->GetTerrain()->IsInWater(prevPos.x, prevPos.y, prevPos.z);
const float step = 2.0f; // step length before next check slope/edge/water
const float maxSlope = 50.0f; // 50(degree) max seem best value for walkable slope
const float MAX_SLOPE_IN_RADIAN = maxSlope / 180.0f * M_PI_F;
float nextZPointEstimation = 1.0f;
float destx = prevPos.x + dist * cos(orientation);
float desty = prevPos.y + dist * sin(orientation);
const uint32 numChecks = ceil(fabs(dist / step));
const float DELTA_X = (destx - prevPos.x) / numChecks;
const float DELTA_Y = (desty - prevPos.y) / numChecks;
for (uint32 i = 1; i < numChecks + 1; ++i)
{
// compute next point average position
nextPos.x = prevPos.x + DELTA_X;
nextPos.y = prevPos.y + DELTA_Y;
nextPos.z = prevPos.z + nextZPointEstimation;
bool isInLiquid = false;
bool isInLiquidTested = false;
bool isOnGround = false;
GridMapLiquidData liquidData;
// try fix height for next position
if (!unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, nextPos.z))
{
// we cant so test if we are on water
if (!unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData))
{
// not in water and cannot get correct height, maybe flying?
//sLog.outString("Can't get height of point %u, point value %s", i, nextPos.toString().c_str());
nextPos = prevPos;
break;
}
else
{
isInLiquid = true;
isInLiquidTested = true;
}
}
else
isOnGround = true; // player is on ground
if (isInLiquid || (!isInLiquidTested && unitTarget->GetMap()->GetTerrain()->IsInWater(nextPos.x, nextPos.y, nextPos.z, &liquidData)))
{
if (!isPrevInLiquid && fabs(liquidData.level - prevPos.z) > 2.0f)
{
// on edge of water with difference a bit to high to continue
//sLog.outString("Ground vs liquid edge detected!");
nextPos = prevPos;
break;
}
if ((liquidData.level - IN_OR_UNDER_LIQUID_RANGE) > nextPos.z)
nextPos.z = prevPos.z; // we are under water so next z equal prev z
else
nextPos.z = liquidData.level - IN_OR_UNDER_LIQUID_RANGE; // we are on water surface, so next z equal liquid level
isInLiquid = true;
float ground = nextPos.z;
if (unitTarget->GetMap()->GetHeightInRange(unitTarget->GetPhaseMask(), nextPos.x, nextPos.y, ground))
{
if (nextPos.z < ground)
{
nextPos.z = ground;
isOnGround = true; // player is on ground of the water
}
}
}
//unitTarget->SummonCreature(VISUAL_WAYPOINT, nextPos.x, nextPos.y, nextPos.z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000);
float hitZ = nextPos.z + 1.5f;
if (unitTarget->GetMap()->GetHitPosition(prevPos.x, prevPos.y, prevPos.z + 1.5f, nextPos.x, nextPos.y, hitZ, unitTarget->GetPhaseMask(), -1.0f))
{
//sLog.outString("Blink collision detected!");
nextPos = prevPos;
break;
}
if (isOnGround)
{
// project vector to get only positive value
float ac = fabs(prevPos.z - nextPos.z);
// compute slope (in radian)
float slope = atan(ac / step);
// check slope value
if (slope > MAX_SLOPE_IN_RADIAN)
{
//sLog.outString("bad slope detected! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
nextPos = prevPos;
break;
}
//sLog.outString("slope is ok! %4.2f max %4.2f, ac(%4.2f)", slope * 180 / M_PI_F, maxSlope, ac);
}
//sLog.outString("point %u is ok, coords %s", i, nextPos.toString().c_str());
nextZPointEstimation = (nextPos.z - prevPos.z) / 2.0f;
isPrevInLiquid = isInLiquid;
prevPos = nextPos;
}
unitTarget->NearTeleportTo(nextPos.x, nextPos.y, nextPos.z, orientation, unitTarget == m_caster);
}
void Spell::EffectLeapBack(SpellEffectEntry const* effect)
{
if (unitTarget->IsTaxiFlying())
return;
m_caster->KnockBackFrom(unitTarget, float(effect->EffectMiscValue) / 10, float(damage) / 10);
}
void Spell::EffectReputation(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* _player = (Player*)unitTarget;
int32 rep_change = m_currentBasePoints[effect->EffectIndex];
uint32 faction_id = effect->EffectMiscValue;
FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
if (!factionEntry)
return;
rep_change = _player->CalculateReputationGain(REPUTATION_SOURCE_SPELL, rep_change, faction_id);
_player->GetReputationMgr().ModifyReputation(factionEntry, rep_change);
}
void Spell::EffectQuestComplete(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
// A few spells has additional value from basepoints, check condition here.
switch (m_spellInfo->Id)
{
case 43458: // Secrets of Nifflevar
{
if (!unitTarget->HasAura(effect->CalculateSimpleValue()))
return;
break;
}
// TODO: implement these!
// "this spell awards credit for the entire raid (all spell targets as this is area target) if just ONE member has both auras (yes, both effect's basepoints)"
// case 72155: // Harvest Blight Specimen
// case 72162: // Harvest Blight Specimen
// break;
default:
break;
}
uint32 quest_id = effect->EffectMiscValue;
((Player*)unitTarget)->AreaExploredOrEventHappens(quest_id);
}
void Spell::EffectSelfResurrect(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->IsAlive())
return;
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!unitTarget->IsInWorld())
return;
uint32 health = 0;
uint32 mana = 0;
// flat case
if (damage < 0)
{
health = uint32(-damage);
mana = effect->EffectMiscValue;
}
// percent case
else
{
health = uint32(damage / 100.0f * unitTarget->GetMaxHealth());
if (unitTarget->GetMaxPower(POWER_MANA) > 0)
mana = uint32(damage / 100.0f * unitTarget->GetMaxPower(POWER_MANA));
}
Player* plr = ((Player*)unitTarget);
plr->ResurrectPlayer(0.0f);
plr->SetHealth(health);
plr->SetPower(POWER_MANA, mana);
plr->SetPower(POWER_RAGE, 0);
plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY));
plr->SpawnCorpseBones();
}
void Spell::EffectSkinning(SpellEffectEntry const* /*effect*/)
{
if (unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Creature* creature = (Creature*) unitTarget;
int32 targetLevel = creature->getLevel();
uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
((Player*)m_caster)->SendLoot(creature->GetObjectGuid(), LOOT_SKINNING);
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel - 10) * 10 : targetLevel * 5;
int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
// Double chances for elites
((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->IsElite() ? 2 : 1);
}
void Spell::EffectCharge(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
// TODO: research more ContactPoint/attack distance.
// 3.666666 instead of ATTACK_DISTANCE(5.0f) in below seem to give more accurate result.
float x, y, z;
unitTarget->GetContactPoint(m_caster, x, y, z, 3.666666f);
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
((Creature*)unitTarget)->StopMoving();
// Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
m_caster->MonsterMoveWithSpeed(x, y, z, 24.f, true, true);
// not all charge effects used in negative spells
if (unitTarget != m_caster && !IsPositiveSpell(m_spellInfo->Id))
m_caster->Attack(unitTarget, true);
}
void Spell::EffectCharge2(SpellEffectEntry const* /*effect*/)
{
float x, y, z;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
{
m_targets.getDestination(x, y, z);
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
((Creature*)unitTarget)->StopMoving();
}
else if (unitTarget && unitTarget != m_caster)
unitTarget->GetContactPoint(m_caster, x, y, z, 3.666666f);
else
return;
// Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
m_caster->MonsterMoveWithSpeed(x, y, z, 24.f, true, true);
// not all charge effects used in negative spells
if (unitTarget && unitTarget != m_caster && !IsPositiveSpell(m_spellInfo->Id))
m_caster->Attack(unitTarget, true);
}
void Spell::EffectKnockBack(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
unitTarget->KnockBackFrom(m_caster, float(effect->EffectMiscValue) / 10, float(damage) / 10);
}
void Spell::EffectSendTaxi(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->ActivateTaxiPathTo(effect->EffectMiscValue, m_spellInfo->Id);
}
void Spell::EffectPlayerPull(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
float x, y, z;
m_caster->GetPosition(x, y, z);
// move back a bit
x = x - (0.6 * cos(m_caster->GetOrientation() + M_PI_F));
y = y - (0.6 * sin(m_caster->GetOrientation() + M_PI_F));
// Try to normalize Z coord because GetContactPoint do nothing with Z axis
unitTarget->UpdateAllowedPositionZ(x, y, z);
float speed = m_spellInfo->speed ? m_spellInfo->speed : 27.0f;
unitTarget->GetMotionMaster()->MoveJump(x, y, z, speed, 2.5f);
}
void Spell::EffectDispelMechanic(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
uint32 mechanic = effect->EffectMiscValue;
Unit::SpellAuraHolderMap& Auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
{
next = iter;
++next;
SpellEntry const* spell = iter->second->GetSpellProto();
if (iter->second->HasMechanic(mechanic))
{
unitTarget->RemoveAurasDueToSpell(spell->Id);
if (Auras.empty())
break;
else
next = Auras.begin();
}
}
}
void Spell::EffectSummonDeadPet(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* _player = (Player*)m_caster;
Pet* pet = _player->GetPet();
if (!pet)
return;
if (pet->IsAlive())
return;
if (damage < 0)
return;
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
pet->SetDeathState(ALIVE);
pet->clearUnitState(UNIT_STAT_ALL_STATE);
pet->SetHealth(uint32(pet->GetMaxHealth() * (float(damage) / 100)));
pet->AIM_Initialize();
// _player->PetSpellInitialize(); -- action bar not removed at death and not required send at revive
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
}
void Spell::EffectSummonAllTotems(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
int32 start_button = ACTION_BUTTON_SHAMAN_TOTEMS_BAR + effect->EffectMiscValue;
int32 amount_buttons = effect->EffectMiscValueB;
for (int32 slot = 0; slot < amount_buttons; ++slot)
if (ActionButton const* actionButton = ((Player*)m_caster)->GetActionButton(start_button + slot))
if (actionButton->GetType() == ACTION_BUTTON_SPELL)
if (uint32 spell_id = actionButton->GetAction())
m_caster->CastSpell(unitTarget, spell_id, true);
}
void Spell::EffectDestroyAllTotems(SpellEffectEntry const* /*effect*/)
{
int32 mana = 0;
for (int slot = 0; slot < MAX_TOTEM_SLOT; ++slot)
{
if (Totem* totem = m_caster->GetTotem(TotemSlot(slot)))
{
if (damage)
{
uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id))
{
uint32 manacost = m_caster->GetCreateMana() * spellInfo->GetManaCostPercentage() / 100;
mana += manacost * damage / 100;
}
}
totem->UnSummon();
}
}
if (mana)
m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
}
void Spell::EffectBreakPlayerTargeting (SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
WorldPacket data(SMSG_CLEAR_TARGET, 8);
data << unitTarget->GetObjectGuid();
unitTarget->SendMessageToSet(&data, false);
}
void Spell::EffectDurabilityDamage(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
int32 slot = effect->EffectMiscValue;
// FIXME: some spells effects have value -1/-2
// Possibly its mean -1 all player equipped items and -2 all items
if (slot < 0)
{
((Player*)unitTarget)->DurabilityPointsLossAll(damage, (slot < -1));
return;
}
// invalid slot value
if (slot >= INVENTORY_SLOT_BAG_END)
return;
if (Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
((Player*)unitTarget)->DurabilityPointsLoss(item, damage);
}
void Spell::EffectDurabilityDamagePCT(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
int32 slot = effect->EffectMiscValue;
// FIXME: some spells effects have value -1/-2
// Possibly its mean -1 all player equipped items and -2 all items
if (slot < 0)
{
((Player*)unitTarget)->DurabilityLossAll(double(damage) / 100.0f, (slot < -1));
return;
}
// invalid slot value
if (slot >= INVENTORY_SLOT_BAG_END)
return;
if (damage <= 0)
return;
if (Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
((Player*)unitTarget)->DurabilityLoss(item, double(damage) / 100.0f);
}
void Spell::EffectModifyThreatPercent(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget)
return;
unitTarget->GetThreatManager().modifyThreatPercent(m_caster, damage);
}
void Spell::EffectTransmitted(SpellEffectEntry const* effect)
{
uint32 name_id = effect->EffectMiscValue;
switch (m_spellInfo->Id)
{
case 29886: // Create Soulwell
if (m_caster->HasAura(18692))
name_id = 183510;
else if (m_caster->HasAura(18693))
name_id = 183511;
break;
default:
break;
}
GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(name_id);
if (!goinfo)
{
sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast", name_id, m_spellInfo->Id);
return;
}
float fx, fy, fz;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(fx, fy, fz);
// FIXME: this can be better check for most objects but still hack
else if (effect->GetRadiusIndex() && m_spellInfo->speed == 0)
{
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
}
else
{
float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
float dis = rand_norm_f() * (max_dis - min_dis) + min_dis;
// special code for fishing bobber (TARGET_SELF_FISHING), should not try to avoid objects
// nor try to find ground level, but randomly vary in angle
if (goinfo->type == GAMEOBJECT_TYPE_FISHINGNODE)
{
// calculate angle variation for roughly equal dimensions of target area
float max_angle = (max_dis - min_dis) / (max_dis + m_caster->GetObjectBoundingRadius());
float angle_offset = max_angle * (rand_norm_f() - 0.5f);
m_caster->GetNearPoint2D(fx, fy, dis + m_caster->GetObjectBoundingRadius(), m_caster->GetOrientation() + angle_offset);
GridMapLiquidData liqData;
if (!m_caster->GetTerrain()->IsInWater(fx, fy, m_caster->GetPositionZ() + 1.f, &liqData))
{
SendCastResult(SPELL_FAILED_NOT_FISHABLE);
SendChannelUpdate(0);
return;
}
fz = liqData.level;
// finally, check LoS
if (!m_caster->IsWithinLOS(fx, fy, fz))
{
SendCastResult(SPELL_FAILED_LINE_OF_SIGHT);
SendChannelUpdate(0);
return;
}
}
else
m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
}
Map* cMap = m_caster->GetMap();
// if gameobject is summoning object, it should be spawned right on caster's position
if (goinfo->type == GAMEOBJECT_TYPE_SUMMONING_RITUAL)
{
m_caster->GetPosition(fx, fy, fz);
}
GameObject* pGameObj = new GameObject;
if (!pGameObj->Create(cMap->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation()))
{
delete pGameObj;
return;
}
int32 duration = m_duration;
switch (goinfo->type)
{
case GAMEOBJECT_TYPE_FISHINGNODE:
{
m_caster->SetChannelObjectGuid(pGameObj->GetObjectGuid());
m_caster->AddGameObject(pGameObj); // will removed at spell cancel
// end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
// start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
int32 lastSec = 0;
switch (urand(0, 3))
{
case 0: lastSec = 3; break;
case 1: lastSec = 7; break;
case 2: lastSec = 13; break;
case 3: lastSec = 17; break;
}
duration = duration - lastSec * IN_MILLISECONDS + FISHING_BOBBER_READY_TIME * IN_MILLISECONDS;
break;
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
{
pGameObj->AddUniqueUse((Player*)m_caster);
m_caster->AddGameObject(pGameObj); // will removed at spell cancel
}
break;
}
case GAMEOBJECT_TYPE_SPELLCASTER:
{
m_caster->AddGameObject(pGameObj);
break;
}
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_CHEST:
default:
break;
}
pGameObj->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
pGameObj->SetOwnerGuid(m_caster->GetObjectGuid());
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
pGameObj->SetSpellId(m_spellInfo->Id);
DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
// m_caster->AddGameObject(pGameObj);
// m_ObjToDel.push_back(pGameObj);
cMap->Add(pGameObj);
pGameObj->SummonLinkedTrapIfAny();
if (m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->AI())
((Creature*)m_caster)->AI()->JustSummoned(pGameObj);
if (m_originalCaster && m_originalCaster != m_caster && m_originalCaster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_originalCaster)->AI())
((Creature*)m_originalCaster)->AI()->JustSummoned(pGameObj);
}
void Spell::EffectProspecting(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER || !itemTarget)
return;
Player* p_caster = (Player*)m_caster;
if (sWorld.getConfig(CONFIG_BOOL_SKILL_PROSPECTING))
{
uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
}
((Player*)m_caster)->SendLoot(itemTarget->GetObjectGuid(), LOOT_PROSPECTING);
}
void Spell::EffectMilling(SpellEffectEntry const* /*effect*/)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER || !itemTarget)
return;
Player* p_caster = (Player*)m_caster;
if (sWorld.getConfig(CONFIG_BOOL_SKILL_MILLING))
{
uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
}
((Player*)m_caster)->SendLoot(itemTarget->GetObjectGuid(), LOOT_MILLING);
}
void Spell::EffectSkill(SpellEffectEntry const* /*effect*/)
{
DEBUG_LOG("WORLD: SkillEFFECT");
}
void Spell::EffectSpiritHeal(SpellEffectEntry const* /*effect*/)
{
// TODO player can't see the heal-animation - he should respawn some ticks later
if (!unitTarget || unitTarget->IsAlive())
return;
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (!unitTarget->IsInWorld())
return;
if (m_spellInfo->Id == 22012 && !unitTarget->HasAura(2584))
return;
((Player*)unitTarget)->ResurrectPlayer(1.0f);
((Player*)unitTarget)->SpawnCorpseBones();
}
// remove insignia spell effect
void Spell::EffectSkinPlayerCorpse(SpellEffectEntry const* /*effect*/)
{
DEBUG_LOG("Effect: SkinPlayerCorpse");
if ((m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->IsAlive()))
return;
((Player*)unitTarget)->RemovedInsignia((Player*)m_caster);
}
void Spell::EffectStealBeneficialBuff(SpellEffectEntry const* effect)
{
DEBUG_LOG("Effect: StealBeneficialBuff");
if (!unitTarget || unitTarget == m_caster) // can't steal from self
return;
typedef std::vector<SpellAuraHolder*> StealList;
StealList steal_list;
// Create dispel mask by dispel type
uint32 dispelMask = GetDispellMask( DispelType(effect->EffectMiscValue) );
Unit::SpellAuraHolderMap const& auras = unitTarget->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellAuraHolder *holder = itr->second;
if (holder && (1<<holder->GetSpellProto()->GetDispel()) & dispelMask)
{
// Need check for passive? this
if (holder->IsPositive() && !holder->IsPassive() && !holder->GetSpellProto()->HasAttribute(SPELL_ATTR_EX4_NOT_STEALABLE))
steal_list.push_back(holder);
}
}
// Ok if exist some buffs for dispel try dispel it
if (!steal_list.empty())
{
typedef std::list < std::pair<uint32, ObjectGuid> > SuccessList;
SuccessList success_list;
int32 list_size = steal_list.size();
// Dispell N = damage buffs (or while exist buffs for dispel)
for (int32 count = 0; count < damage && list_size > 0; ++count)
{
// Random select buff for dispel
SpellAuraHolder* holder = steal_list[urand(0, list_size - 1)];
// Not use chance for steal
// TODO possible need do it
success_list.push_back(SuccessList::value_type(holder->GetId(), holder->GetCasterGuid()));
// Remove buff from list for prevent doubles
for (StealList::iterator j = steal_list.begin(); j != steal_list.end();)
{
SpellAuraHolder* stealed = *j;
if (stealed->GetId() == holder->GetId() && stealed->GetCasterGuid() == holder->GetCasterGuid())
{
j = steal_list.erase(j);
--list_size;
}
else
++j;
}
}
// Really try steal and send log
if (!success_list.empty())
{
int32 count = success_list.size();
WorldPacket data(SMSG_SPELLSTEALLOG, 8 + 8 + 4 + 1 + 4 + count * 5);
data << unitTarget->GetPackGUID(); // Victim GUID
data << m_caster->GetPackGUID(); // Caster GUID
data << uint32(m_spellInfo->Id); // Dispell spell id
data << uint8(0); // not used
data << uint32(count); // count
for (SuccessList::iterator j = success_list.begin(); j != success_list.end(); ++j)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
data << uint32(spellInfo->Id); // Spell Id
data << uint8(0); // 0 - steals !=0 transfers
unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
}
m_caster->SendMessageToSet(&data, true);
}
}
}
void Spell::EffectWMODamage(SpellEffectEntry const* effect)
{
DEBUG_LOG("Effect: WMODamage");
if (!gameObjTarget)
return;
if (gameObjTarget->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
{
sLog.outError("Spell::EffectWMODamage called without valid targets. Spell Id %u", m_spellInfo->Id);
return;
}
if (!gameObjTarget->GetHealth())
return;
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
DEBUG_LOG("Spell::EffectWMODamage, spell Id %u, go entry %u, damage %u", m_spellInfo->Id, gameObjTarget->GetEntry(), uint32(damage));
gameObjTarget->DealGameObjectDamage(uint32(damage), m_spellInfo->Id, caster);
}
void Spell::EffectWMORepair(SpellEffectEntry const* effect)
{
DEBUG_LOG("Effect: WMORepair");
if (!gameObjTarget)
return;
if (gameObjTarget->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
{
sLog.outError("Spell::EffectWMORepair called without valid targets. Spell Id %u", m_spellInfo->Id);
return;
}
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
DEBUG_LOG("Spell::EffectWMORepair, spell Id %u, go entry %u", m_spellInfo->Id, gameObjTarget->GetEntry());
gameObjTarget->RebuildGameObject(m_spellInfo->Id, caster);
}
void Spell::EffectWMOChange(SpellEffectEntry const* effect)
{
DEBUG_LOG("Effect: WMOChange");
if (!gameObjTarget)
return;
if (gameObjTarget->GetGoType() != GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
{
sLog.outError("Spell::EffectWMOChange called without valid targets. Spell Id %u", m_spellInfo->Id);
return;
}
DEBUG_LOG("Spell::EffectWMOChange, spell Id %u, object %u, misc-value %u", m_spellInfo->Id, gameObjTarget->GetEntry(), effect->EffectMiscValue);
Unit* caster = GetAffectiveCaster();
if (!caster)
return;
switch (effect->EffectMiscValue)
{
case 0: // Set to full health
gameObjTarget->ForceGameObjectHealth(gameObjTarget->GetMaxHealth(), caster);
break;
case 1: // Set to damaged
gameObjTarget->ForceGameObjectHealth(gameObjTarget->GetGOInfo()->destructibleBuilding.damagedNumHits, caster);
break;
case 2: // Set to destroyed
gameObjTarget->ForceGameObjectHealth(-int32(gameObjTarget->GetHealth()), caster);
break;
case 3: // Set to rebuilding
gameObjTarget->ForceGameObjectHealth(0, caster);
break;
default:
sLog.outError("Spell::EffectWMOChange, spell Id %u with undefined change value %u", m_spellInfo->Id, effect->EffectMiscValue);
break;
}
}
void Spell::EffectKillCreditPersonal(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->KilledMonsterCredit(effect->EffectMiscValue);
}
void Spell::EffectKillCreditGroup(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->RewardPlayerAndGroupAtEvent(effect->EffectMiscValue, unitTarget);
}
void Spell::EffectQuestFail(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->FailQuest(effect->EffectMiscValue);
}
void Spell::EffectActivateRune(SpellEffectEntry const* effect)
{
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* plr = (Player*)m_caster;
if (plr->getClass() != CLASS_DEATH_KNIGHT)
return;
int32 count = damage; // max amount of reset runes
plr->ResyncRunes();
}
void Spell::EffectTitanGrip(SpellEffectEntry const* effect)
{
// Make sure "Titan's Grip" (49152) penalty spell does not silently change
if (effect->EffectMiscValue != 49152)
sLog.outError("Spell::EffectTitanGrip: Spell %u has unexpected EffectMiscValue '%u'", m_spellInfo->Id, effect->EffectMiscValue);
if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
{
Player* plr = (Player*)m_caster;
plr->SetCanTitanGrip(true);
if (plr->HasTwoHandWeaponInOneHand() && !plr->HasAura(49152))
plr->CastSpell(plr, 49152, true);
}
}
void Spell::EffectRenamePet(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
!((Creature*)unitTarget)->IsPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
return;
unitTarget->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
}
void Spell::EffectPlaySound(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 soundId = effect->EffectMiscValue;
if (!sSoundEntriesStore.LookupEntry(soundId))
{
sLog.outError("EffectPlaySound: Sound (Id: %u) in spell %u does not exist.", soundId, m_spellInfo->Id);
return;
}
unitTarget->PlayDirectSound(soundId, (Player*)unitTarget);
}
void Spell::EffectPlayMusic(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 soundId = effect->EffectMiscValue;
if (!sSoundEntriesStore.LookupEntry(soundId))
{
sLog.outError("EffectPlayMusic: Sound (Id: %u) in spell %u does not exist.", soundId, m_spellInfo->Id);
return;
}
m_caster->PlayMusic(soundId, (Player*)unitTarget);
}
void Spell::EffectSpecCount(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)unitTarget)->UpdateSpecCount(damage);
}
void Spell::EffectActivateSpec(SpellEffectEntry const* /*effect*/)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
uint32 spec = damage - 1;
((Player*)unitTarget)->ActivateSpec(spec);
}
void Spell::EffectBind(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)unitTarget;
uint32 area_id = uint32(effect->EffectMiscValue);
WorldLocation loc;
if (effect->EffectImplicitTargetA == TARGET_TABLE_X_Y_Z_COORDINATES ||
effect->EffectImplicitTargetB == TARGET_TABLE_X_Y_Z_COORDINATES)
{
SpellTargetPosition const* st = sSpellMgr.GetSpellTargetPosition(m_spellInfo->Id);
if (!st)
{
sLog.outError("Spell::EffectBind - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id);
return;
}
loc.mapid = st->target_mapId;
loc.coord_x = st->target_X;
loc.coord_y = st->target_Y;
loc.coord_z = st->target_Z;
loc.orientation = st->target_Orientation;
if (!area_id)
area_id = sTerrainMgr.GetAreaId(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z);
}
else
{
player->GetPosition(loc);
if (!area_id)
area_id = player->GetAreaId();
}
player->SetHomebindToLocation(loc, area_id);
// binding
WorldPacket data(SMSG_BINDPOINTUPDATE, (4 + 4 + 4 + 4 + 4));
data << float(loc.coord_x);
data << float(loc.coord_y);
data << float(loc.coord_z);
data << uint32(loc.mapid);
data << uint32(area_id);
player->SendDirectMessage(&data);
DEBUG_LOG("New Home Position for %s: XYZ: %f %f %f on Map %u", player->GetGuidStr().c_str(), loc.coord_x, loc.coord_y, loc.coord_z, loc.mapid);
// zone update
data.Initialize(SMSG_PLAYERBOUND, 8 + 4);
data << m_caster->GetObjectGuid();
data << uint32(area_id);
player->SendDirectMessage(&data);
}
void Spell::EffectRestoreItemCharges(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)unitTarget;
ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(effect->EffectItemType);
if (!itemProto)
return;
// In case item from limited category recharge any from category, is this valid checked early in spell checks
Item* item;
if (itemProto->ItemLimitCategory)
item = ((Player*)unitTarget)->GetItemByLimitedCategory(itemProto->ItemLimitCategory);
else
item = player->GetItemByEntry(effect->EffectItemType);
if (!item)
return;
item->RestoreCharges();
}
void Spell::EffectRedirectThreat(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
if (m_spellInfo->Id == 59665) // Vigilance
if (Aura* glyph = unitTarget->GetDummyAura(63326)) // Glyph of Vigilance
damage += glyph->GetModifier()->m_amount;
m_caster->getHostileRefManager().SetThreatRedirection(unitTarget->GetObjectGuid(), uint32(damage));
}
void Spell::EffectTeachTaxiNode(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
Player* player = (Player*)unitTarget;
uint32 taxiNodeId = effect->EffectMiscValue;
if (!sTaxiNodesStore.LookupEntry(taxiNodeId))
return;
if (player->m_taxi.SetTaximaskNode(taxiNodeId))
{
WorldPacket data(SMSG_NEW_TAXI_PATH, 0);
player->SendDirectMessage(&data);
data.Initialize(SMSG_TAXINODE_STATUS, 9);
data << m_caster->GetObjectGuid();
data << uint8(1);
player->SendDirectMessage(&data);
}
}
void Spell::EffectQuestOffer(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
if (Quest const* quest = sObjectMgr.GetQuestTemplate(effect->EffectMiscValue))
{
Player* player = (Player*)unitTarget;
if (player->CanTakeQuest(quest, false))
player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, player->GetObjectGuid(), true);
}
}
void Spell::EffectCancelAura(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
uint32 spellId = effect->EffectTriggerSpell;
if (!sSpellStore.LookupEntry(spellId))
{
sLog.outError("Spell::EffectCancelAura: spell %u doesn't exist", spellId);
return;
}
unitTarget->RemoveAurasDueToSpell(spellId);
}
void Spell::EffectKnockBackFromPosition(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
float x, y, z;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(x, y, z);
else
m_caster->GetPosition(x, y, z);
float angle = unitTarget->GetAngle(x, y) + M_PI_F;
float horizontalSpeed = effect->EffectMiscValue * 0.1f;
float verticalSpeed = damage * 0.1f;
unitTarget->KnockBackWithAngle(angle, horizontalSpeed, verticalSpeed);
}
void Spell::EffectGravityPull(SpellEffectEntry const* effect)
{
if (!unitTarget)
return;
float x, y, z;
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
m_targets.getDestination(x, y, z);
else
m_caster->GetPosition(x, y, z);
float speed = float(effect->EffectMiscValue) * 0.15f;
float height = float(unitTarget->GetDistance(x, y, z) * 0.2f);
unitTarget->GetMotionMaster()->MoveJump(x, y, z, speed, height);
}
void Spell::EffectCreateTamedPet(SpellEffectEntry const* effect)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->getClass() != CLASS_HUNTER)
return;
uint32 creatureEntry = effect->EffectMiscValue;
CreatureInfo const* cInfo = ObjectMgr::GetCreatureTemplate(creatureEntry);
if (creatureEntry && !cInfo)
{
sLog.outErrorDb("EffectCreateTamedPet: Creature entry %u not found for spell %u.", creatureEntry, m_spellInfo->Id);
return;
}
Pet* newTamedPet = new Pet;
CreatureCreatePos pos(unitTarget, unitTarget->GetOrientation());
Map* map = unitTarget->GetMap();
uint32 petNumber = sObjectMgr.GeneratePetNumber();
if (!newTamedPet->Create(map->GenerateLocalLowGuid(HIGHGUID_PET), pos, cInfo, petNumber))
{
delete newTamedPet;
return;
}
newTamedPet->SetRespawnCoord(pos);
newTamedPet->setPetType(HUNTER_PET);
newTamedPet->SetOwnerGuid(unitTarget->GetObjectGuid());
newTamedPet->SetCreatorGuid(unitTarget->GetObjectGuid());
newTamedPet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
newTamedPet->setFaction(unitTarget->getFaction());
newTamedPet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL)));
newTamedPet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
newTamedPet->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
newTamedPet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
newTamedPet->GetCharmInfo()->SetPetNumber(petNumber, true);
if (unitTarget->IsPvP())
newTamedPet->SetPvP(true);
if (unitTarget->IsFFAPvP())
newTamedPet->SetFFAPvP(true);
newTamedPet->InitStatsForLevel(unitTarget->getLevel(), unitTarget);
newTamedPet->InitPetCreateSpells();
newTamedPet->InitLevelupSpellsForLevel();
newTamedPet->InitTalentForLevel();
newTamedPet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
newTamedPet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_ABANDONED);
newTamedPet->AIM_Initialize();
newTamedPet->SetHealth(newTamedPet->GetMaxHealth());
newTamedPet->SetPower(POWER_MANA, newTamedPet->GetMaxPower(POWER_MANA));
float x, y, z;
unitTarget->GetClosePoint(x, y, z, newTamedPet->GetObjectBoundingRadius());
newTamedPet->Relocate(x, y, z, unitTarget->GetOrientation());
map->Add((Creature*)newTamedPet);
m_caster->SetPet(newTamedPet);
newTamedPet->SavePetToDB(PET_SAVE_AS_CURRENT);
((Player*)unitTarget)->PetSpellInitialize();
}