Core/Spells: Implemented personal summons (#19231)
[trinitycore] / src / server / game / Spells / SpellEffects.cpp
1 /*
2 * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
3 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "Spell.h"
20 #include "AccountMgr.h"
21 #include "AreaTrigger.h"
22 #include "Battleground.h"
23 #include "BattlegroundMgr.h"
24 #include "BattlePetMgr.h"
25 #include "CombatLogPackets.h"
26 #include "CombatPackets.h"
27 #include "Common.h"
28 #include "Conversation.h"
29 #include "Creature.h"
30 #include "CreatureAI.h"
31 #include "DatabaseEnv.h"
32 #include "DB2Stores.h"
33 #include "DuelPackets.h"
34 #include "DynamicObject.h"
35 #include "GameObject.h"
36 #include "GameObjectAI.h"
37 #include "Garrison.h"
38 #include "GossipDef.h"
39 #include "Group.h"
40 #include "Guild.h"
41 #include "InstanceScript.h"
42 #include "Item.h"
43 #include "Language.h"
44 #include "Log.h"
45 #include "LootMgr.h"
46 #include "Map.h"
47 #include "MiscPackets.h"
48 #include "MotionMaster.h"
49 #include "ObjectMgr.h"
50 #include "Opcodes.h"
51 #include "OutdoorPvPMgr.h"
52 #include "PathGenerator.h"
53 #include "Pet.h"
54 #include "PhasingHandler.h"
55 #include "Player.h"
56 #include "ReputationMgr.h"
57 #include "ScriptMgr.h"
58 #include "SharedDefines.h"
59 #include "SkillExtraItems.h"
60 #include "SocialMgr.h"
61 #include "SpellAuraEffects.h"
62 #include "SpellAuras.h"
63 #include "SpellHistory.h"
64 #include "SpellMgr.h"
65 #include "SpellPackets.h"
66 #include "TalentPackets.h"
67 #include "TemporarySummon.h"
68 #include "Totem.h"
69 #include "Unit.h"
70 #include "Util.h"
71 #include "World.h"
72 #include "WorldPacket.h"
73 #include "WorldSession.h"
74
75 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
76 {
77 &Spell::EffectNULL, // 0
78 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
79 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
80 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
81 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
82 &Spell::EffectUnused, // 5 SPELL_EFFECT_TELEPORT_UNITS_OLD
83 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
84 &Spell::EffectEnvironmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
85 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
86 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
87 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
88 &Spell::EffectBind, // 11 SPELL_EFFECT_BIND
89 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
90 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
91 &Spell::EffectUnused, // 14 SPELL_EFFECT_INCREASE_CURRENCY_CAP
92 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
93 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
94 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
95 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
96 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
97 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
98 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
99 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
100 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
101 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
102 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
103 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
104 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
105 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
106 &Spell::EffectLeap, // 29 SPELL_EFFECT_LEAP
107 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
108 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
109 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
110 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
111 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
112 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
113 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
114 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
115 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
116 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
117 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
118 &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP
119 &Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST
120 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
121 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
122 &Spell::EffectPlayMovie, // 45 SPELL_EFFECT_PLAY_MOVIE
123 &Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned
124 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
125 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
126 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
127 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
128 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
129 &Spell::EffectUnused, // 52 SPELL_EFFECT_SET_MAX_BATTLE_PET_COUNT
130 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
131 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
132 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
133 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
134 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
135 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
136 &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot
137 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
138 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
139 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
140 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
141 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
142 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
143 &Spell::EffectRechargeItem, // 66 SPELL_EFFECT_RECHARGE_ITEM
144 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
145 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
146 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
147 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
148 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
149 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
150 &Spell::EffectUntrainTalents, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
151 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
152 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
153 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
154 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
155 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
156 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
157 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
158 &Spell::EffectUnused, // 81 SPELL_EFFECT_PUSH_ABILITY_TO_ACTION_BAR
159 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
160 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
161 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
162 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
163 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
164 &Spell::EffectGameObjectDamage, // 87 SPELL_EFFECT_GAMEOBJECT_DAMAGE
165 &Spell::EffectGameObjectRepair, // 88 SPELL_EFFECT_GAMEOBJECT_REPAIR
166 &Spell::EffectGameObjectSetDestructionState, // 89 SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE
167 &Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person
168 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
169 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
170 &Spell::EffectForceDeselect, // 93 SPELL_EFFECT_FORCE_DESELECT
171 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
172 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
173 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
174 &Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a)
175 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
176 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
177 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
178 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
179 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
180 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
181 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
182 &Spell::EffectUnused, //105 SPELL_EFFECT_SURVEY
183 &Spell::EffectChangeRaidMarker, //106 SPELL_EFFECT_CHANGE_RAID_MARKER
184 &Spell::EffectUnused, //107 SPELL_EFFECT_SHOW_CORPSE_LOOT
185 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
186 &Spell::EffectResurrectPet, //109 SPELL_EFFECT_RESURRECT_PET
187 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
188 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
189 &Spell::EffectUnused, //112 SPELL_EFFECT_112
190 &Spell::EffectUnused, //113 SPELL_EFFECT_113
191 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
192 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
193 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
194 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
195 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
196 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
197 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
198 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
199 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
200 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
201 &Spell::EffectPullTowards, //124 SPELL_EFFECT_PULL_TOWARDS
202 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
203 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
204 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
205 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
206 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
207 &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
208 &Spell::EffectPlaySound, //131 SPELL_EFFECT_PLAY_SOUND sound id in misc value (SoundEntries.dbc)
209 &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
210 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
211 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
212 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
213 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
214 &Spell::EffectEnergizePct, //137 SPELL_EFFECT_ENERGIZE_PCT
215 &Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back
216 &Spell::EffectQuestClear, //139 SPELL_EFFECT_CLEAR_QUEST Reset quest status (miscValue - quest ID)
217 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
218 &Spell::EffectForceCast, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE
219 &Spell::EffectTriggerSpell, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
220 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
221 &Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_DEST
222 &Spell::EffectPullTowards, //145 SPELL_EFFECT_PULL_TOWARDS_DEST Black Hole Effect
223 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
224 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
225 &Spell::EffectTriggerMissileSpell, //148 SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE
226 &Spell::EffectChargeDest, //149 SPELL_EFFECT_CHARGE_DEST
227 &Spell::EffectQuestStart, //150 SPELL_EFFECT_QUEST_START
228 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
229 &Spell::EffectSummonRaFFriend, //152 SPELL_EFFECT_SUMMON_RAF_FRIEND summon Refer-a-Friend
230 &Spell::EffectCreateTamedPet, //153 SPELL_EFFECT_CREATE_TAMED_PET misc value is creature entry
231 &Spell::EffectDiscoverTaxi, //154 SPELL_EFFECT_DISCOVER_TAXI
232 &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.
233 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
234 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item
235 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
236 &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
237 &Spell::EffectForceCast, //160 SPELL_EFFECT_FORCE_CAST_2
238 &Spell::EffectNULL, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert)
239 &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec
240 &Spell::EffectUnused, //163 SPELL_EFFECT_OBLITERATE_ITEM
241 &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA
242 &Spell::EffectDamageFromMaxHealthPCT, //165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT
243 &Spell::EffectGiveCurrency, //166 SPELL_EFFECT_GIVE_CURRENCY
244 &Spell::EffectUpdatePlayerPhase, //167 SPELL_EFFECT_UPDATE_PLAYER_PHASE
245 &Spell::EffectNULL, //168 SPELL_EFFECT_ALLOW_CONTROL_PET
246 &Spell::EffectDestroyItem, //169 SPELL_EFFECT_DESTROY_ITEM
247 &Spell::EffectUpdateZoneAurasAndPhases, //170 SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES
248 &Spell::EffectNULL, //171 SPELL_EFFECT_171
249 &Spell::EffectResurrectWithAura, //172 SPELL_EFFECT_RESURRECT_WITH_AURA
250 &Spell::EffectUnlockGuildVaultTab, //173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB
251 &Spell::EffectNULL, //174 SPELL_EFFECT_APPLY_AURA_ON_PET
252 &Spell::EffectUnused, //175 SPELL_EFFECT_175 unused
253 &Spell::EffectSanctuary, //176 SPELL_EFFECT_SANCTUARY_2
254 &Spell::EffectNULL, //177 SPELL_EFFECT_177
255 &Spell::EffectUnused, //178 SPELL_EFFECT_178 unused
256 &Spell::EffectCreateAreaTrigger, //179 SPELL_EFFECT_CREATE_AREATRIGGER
257 &Spell::EffectNULL, //180 SPELL_EFFECT_UPDATE_AREATRIGGER
258 &Spell::EffectRemoveTalent, //181 SPELL_EFFECT_REMOVE_TALENT
259 &Spell::EffectNULL, //182 SPELL_EFFECT_DESPAWN_AREATRIGGER
260 &Spell::EffectNULL, //183 SPELL_EFFECT_183
261 &Spell::EffectNULL, //184 SPELL_EFFECT_REPUTATION
262 &Spell::EffectNULL, //185 SPELL_EFFECT_185
263 &Spell::EffectNULL, //186 SPELL_EFFECT_186
264 &Spell::EffectNULL, //187 SPELL_EFFECT_RANDOMIZE_ARCHAEOLOGY_DIGSITES
265 &Spell::EffectNULL, //188 SPELL_EFFECT_188
266 &Spell::EffectNULL, //189 SPELL_EFFECT_LOOT
267 &Spell::EffectNULL, //190 SPELL_EFFECT_190
268 &Spell::EffectNULL, //191 SPELL_EFFECT_TELEPORT_TO_DIGSITE
269 &Spell::EffectUncageBattlePet, //192 SPELL_EFFECT_UNCAGE_BATTLEPET
270 &Spell::EffectNULL, //193 SPELL_EFFECT_START_PET_BATTLE
271 &Spell::EffectNULL, //194 SPELL_EFFECT_194
272 &Spell::EffectNULL, //195 SPELL_EFFECT_195
273 &Spell::EffectNULL, //196 SPELL_EFFECT_196
274 &Spell::EffectNULL, //197 SPELL_EFFECT_197
275 &Spell::EffectPlayScene, //198 SPELL_EFFECT_PLAY_SCENE
276 &Spell::EffectNULL, //199 SPELL_EFFECT_199
277 &Spell::EffectHealBattlePetPct, //200 SPELL_EFFECT_HEAL_BATTLEPET_PCT
278 &Spell::EffectEnableBattlePets, //201 SPELL_EFFECT_ENABLE_BATTLE_PETS
279 &Spell::EffectNULL, //202 SPELL_EFFECT_202
280 &Spell::EffectNULL, //203 SPELL_EFFECT_203
281 &Spell::EffectNULL, //204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY
282 &Spell::EffectLaunchQuestChoice, //205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE
283 &Spell::EffectNULL, //206 SPELL_EFFECT_ALTER_ITEM
284 &Spell::EffectNULL, //207 SPELL_EFFECT_LAUNCH_QUEST_TASK
285 &Spell::EffectNULL, //208 SPELL_EFFECT_208
286 &Spell::EffectNULL, //209 SPELL_EFFECT_209
287 &Spell::EffectLearnGarrisonBuilding, //210 SPELL_EFFECT_LEARN_GARRISON_BUILDING
288 &Spell::EffectNULL, //211 SPELL_EFFECT_LEARN_GARRISON_SPECIALIZATION
289 &Spell::EffectNULL, //212 SPELL_EFFECT_212
290 &Spell::EffectNULL, //213 SPELL_EFFECT_213
291 &Spell::EffectCreateGarrison, //214 SPELL_EFFECT_CREATE_GARRISON
292 &Spell::EffectNULL, //215 SPELL_EFFECT_UPGRADE_CHARACTER_SPELLS
293 &Spell::EffectNULL, //216 SPELL_EFFECT_CREATE_SHIPMENT
294 &Spell::EffectNULL, //217 SPELL_EFFECT_UPGRADE_GARRISON
295 &Spell::EffectNULL, //218 SPELL_EFFECT_218
296 &Spell::EffectCreateConversation, //219 SPELL_EFFECT_CREATE_CONVERSATION
297 &Spell::EffectAddGarrisonFollower, //220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER
298 &Spell::EffectNULL, //221 SPELL_EFFECT_221
299 &Spell::EffectCreateHeirloomItem, //222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
300 &Spell::EffectNULL, //223 SPELL_EFFECT_CHANGE_ITEM_BONUSES
301 &Spell::EffectActivateGarrisonBuilding, //224 SPELL_EFFECT_ACTIVATE_GARRISON_BUILDING
302 &Spell::EffectNULL, //225 SPELL_EFFECT_GRANT_BATTLEPET_LEVEL
303 &Spell::EffectNULL, //226 SPELL_EFFECT_226
304 &Spell::EffectNULL, //227 SPELL_EFFECT_TELEPORT_TO_LFG_DUNGEON
305 &Spell::EffectNULL, //228 SPELL_EFFECT_228
306 &Spell::EffectNULL, //229 SPELL_EFFECT_SET_FOLLOWER_QUALITY
307 &Spell::EffectNULL, //230 SPELL_EFFECT_INCREASE_FOLLOWER_ITEM_LEVEL
308 &Spell::EffectNULL, //231 SPELL_EFFECT_INCREASE_FOLLOWER_EXPERIENCE
309 &Spell::EffectNULL, //232 SPELL_EFFECT_REMOVE_PHASE
310 &Spell::EffectNULL, //233 SPELL_EFFECT_RANDOMIZE_FOLLOWER_ABILITIES
311 &Spell::EffectNULL, //234 SPELL_EFFECT_234
312 &Spell::EffectNULL, //235 SPELL_EFFECT_235
313 &Spell::EffectNULL, //236 SPELL_EFFECT_GIVE_EXPERIENCE
314 &Spell::EffectNULL, //237 SPELL_EFFECT_GIVE_RESTED_EXPERIENCE_BONUS
315 &Spell::EffectNULL, //238 SPELL_EFFECT_INCREASE_SKILL
316 &Spell::EffectNULL, //239 SPELL_EFFECT_END_GARRISON_BUILDING_CONSTRUCTION
317 &Spell::EffectGiveArtifactPower, //240 SPELL_EFFECT_GIVE_ARTIFACT_POWER
318 &Spell::EffectNULL, //241 SPELL_EFFECT_241
319 &Spell::EffectGiveArtifactPowerNoBonus, //242 SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS
320 &Spell::EffectApplyEnchantIllusion, //243 SPELL_EFFECT_APPLY_ENCHANT_ILLUSION
321 &Spell::EffectNULL, //244 SPELL_EFFECT_LEARN_FOLLOWER_ABILITY
322 &Spell::EffectUpgradeHeirloom, //245 SPELL_EFFECT_UPGRADE_HEIRLOOM
323 &Spell::EffectNULL, //246 SPELL_EFFECT_FINISH_GARRISON_MISSION
324 &Spell::EffectNULL, //247 SPELL_EFFECT_ADD_GARRISON_MISSION
325 &Spell::EffectNULL, //248 SPELL_EFFECT_FINISH_SHIPMENT
326 &Spell::EffectNULL, //249 SPELL_EFFECT_FORCE_EQUIP_ITEM
327 &Spell::EffectNULL, //250 SPELL_EFFECT_TAKE_SCREENSHOT
328 &Spell::EffectNULL, //251 SPELL_EFFECT_SET_GARRISON_CACHE_SIZE
329 &Spell::EffectTeleportUnits, //252 SPELL_EFFECT_TELEPORT_UNITS
330 &Spell::EffectGiveHonor, //253 SPELL_EFFECT_GIVE_HONOR
331 &Spell::EffectNULL, //254 SPELL_EFFECT_254
332 &Spell::EffectLearnTransmogSet, //255 SPELL_EFFECT_LEARN_TRANSMOG_SET
333 };
334
335 void Spell::EffectNULL(SpellEffIndex /*effIndex*/)
336 {
337 TC_LOG_DEBUG("spells", "WORLD: Spell Effect DUMMY");
338 }
339
340 void Spell::EffectUnused(SpellEffIndex /*effIndex*/)
341 {
342 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN TRINITY
343 }
344
345 void Spell::EffectResurrectNew(SpellEffIndex effIndex)
346 {
347 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
348 return;
349
350 if (!unitTarget || unitTarget->IsAlive())
351 return;
352
353 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
354 return;
355
356 if (!unitTarget->IsInWorld())
357 return;
358
359 Player* target = unitTarget->ToPlayer();
360
361 if (target->IsResurrectRequested()) // already have one active request
362 return;
363
364 uint32 health = damage;
365 uint32 mana = effectInfo->MiscValue;
366 ExecuteLogEffectResurrect(effIndex, target);
367 target->SetResurrectRequestData(m_caster, health, mana, 0);
368 SendResurrectRequest(target);
369 }
370
371 void Spell::EffectInstaKill(SpellEffIndex /*effIndex*/)
372 {
373 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
374 return;
375
376 if (!unitTarget || !unitTarget->IsAlive())
377 return;
378
379 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
380 if (unitTarget->ToPlayer()->GetCommandStatus(CHEAT_GOD))
381 return;
382
383 if (m_caster == unitTarget) // prevent interrupt message
384 finish();
385
386 WorldPackets::CombatLog::SpellInstakillLog data;
387 data.Target = unitTarget->GetGUID();
388 data.Caster = m_caster->GetGUID();
389 data.SpellID = m_spellInfo->Id;
390
391 m_caster->SendMessageToSet(data.Write(), true);
392
393 m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
394 }
395
396 void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
397 {
398 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
399 return;
400
401 if (!unitTarget || !unitTarget->IsAlive())
402 return;
403
404 // CalcAbsorbResist already in Player::EnvironmentalDamage
405 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
406 unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
407 else
408 {
409 DamageInfo damageInfo(m_caster, unitTarget, damage, m_spellInfo, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
410 m_caster->CalcAbsorbResist(damageInfo);
411
412 SpellNonMeleeDamage log(m_caster, unitTarget, m_spellInfo->Id, m_SpellVisual, m_spellInfo->GetSchoolMask(), m_castId);
413 log.damage = damage;
414 log.absorb = damageInfo.GetAbsorb();
415 log.resist = damageInfo.GetResist();
416
417 m_caster->SendSpellNonMeleeDamageLog(&log);
418 }
419 }
420
421 void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
422 {
423 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
424 return;
425
426 if (unitTarget && unitTarget->IsAlive())
427 {
428 bool apply_direct_bonus = true;
429
430 // Meteor like spells (divided damage to targets)
431 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
432 {
433 uint32 count = std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effIndex](TargetInfo const& targetInfo)
434 {
435 return targetInfo.effectMask & (1 << effIndex);
436 });
437
438 // divide to all targets
439 if (count)
440 damage /= count;
441 }
442
443 switch (m_spellInfo->SpellFamilyName)
444 {
445 case SPELLFAMILY_GENERIC:
446 {
447 switch (m_spellInfo->Id) // better way to check unknown
448 {
449 // Consumption
450 case 28865:
451 damage = (m_caster->GetMap()->GetDifficultyID() == DIFFICULTY_NONE ? 2750 : 4250);
452 break;
453 // percent from health with min
454 case 25599: // Thundercrash
455 {
456 damage = unitTarget->GetHealth() / 2;
457 if (damage < 200)
458 damage = 200;
459 break;
460 }
461 // arcane charge. must only affect demons (also undead?)
462 case 45072:
463 {
464 if (unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON
465 && unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
466 return;
467 break;
468 }
469 // Gargoyle Strike
470 case 51963:
471 {
472 // about +4 base spell dmg per level
473 damage = (m_caster->getLevel() - 60) * 4 + 60;
474 break;
475 }
476 }
477 break;
478 }
479 case SPELLFAMILY_WARRIOR:
480 {
481 // Victory Rush
482 if (m_spellInfo->Id == 34428)
483 ApplyPct(damage, m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
484 // Shockwave
485 else if (m_spellInfo->Id == 46968)
486 {
487 int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2);
488 if (pct > 0)
489 damage += int32(CalculatePct(m_caster->GetTotalAttackPowerValue(BASE_ATTACK), pct));
490 break;
491 }
492 break;
493 }
494 case SPELLFAMILY_WARLOCK:
495 {
496 break;
497 }
498 case SPELLFAMILY_PRIEST:
499 {
500 break;
501 }
502 case SPELLFAMILY_DRUID:
503 {
504 // Ferocious Bite
505 if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->SpellFamilyFlags[3] & 0x1000)
506 {
507 // converts each extra point of energy ( up to 25 energy ) into additional damage
508 int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -25));
509 // 25 energy = 100% more damage
510 AddPct(damage, energy * 4);
511 }
512 break;
513 }
514 case SPELLFAMILY_DEATHKNIGHT:
515 {
516 // Blood Boil - bonus for diseased targets
517 if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000)
518 {
519 if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, flag128(0, 0, 0x00000002), m_caster->GetGUID()))
520 {
521 damage += m_damage / 2;
522 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.035f);
523 }
524 }
525 break;
526 }
527 }
528
529 if (m_originalCaster && apply_direct_bonus)
530 {
531 uint32 bonus = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo);
532 damage = bonus + uint32(bonus * variance);
533 damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo);
534 }
535
536 m_damage += damage;
537 }
538 }
539
540 void Spell::EffectDummy(SpellEffIndex effIndex)
541 {
542 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
543 return;
544
545 if (!unitTarget && !gameObjTarget && !itemTarget)
546 return;
547
548 // selection by spell family
549 switch (m_spellInfo->SpellFamilyName)
550 {
551 case SPELLFAMILY_PALADIN:
552 switch (m_spellInfo->Id)
553 {
554 case 31789: // Righteous Defense (step 1)
555 {
556 // Clear targets for eff 1
557 for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
558 ihit->effectMask &= ~(1<<1);
559
560 // not empty (checked), copy
561 Unit::AttackerSet attackers = unitTarget->getAttackers();
562
563 // remove invalid attackers
564 for (Unit::AttackerSet::iterator aItr = attackers.begin(); aItr != attackers.end();)
565 if (!(*aItr)->IsValidAttackTarget(m_caster))
566 attackers.erase(aItr++);
567 else
568 ++aItr;
569
570 // selected from list 3
571 uint32 maxTargets = std::min<uint32>(3, attackers.size());
572 for (uint32 i = 0; i < maxTargets; ++i)
573 {
574 Unit* attacker = Trinity::Containers::SelectRandomContainerElement(attackers);
575 AddUnitTarget(attacker, 1 << 1);
576 attackers.erase(attacker);
577 }
578
579 // now let next effect cast spell at each target.
580 return;
581 }
582 }
583 break;
584 default:
585 break;
586 }
587
588 // pet auras
589 if (PetAura const* petSpell = sSpellMgr->GetPetAura(m_spellInfo->Id, effIndex))
590 {
591 m_caster->AddPetAura(petSpell);
592 return;
593 }
594
595 // normal DB scripted effect
596 TC_LOG_DEBUG("spells", "Spell ScriptStart spellid %u in EffectDummy(%u)", m_spellInfo->Id, effIndex);
597 m_caster->GetMap()->ScriptsStart(sSpellScripts, uint32(m_spellInfo->Id | (effIndex << 24)), m_caster, unitTarget);
598
599 // Script based implementation. Must be used only for not good for implementation in core spell effects
600 // So called only for not proccessed cases
601 if (gameObjTarget)
602 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, gameObjTarget);
603 else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
604 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, unitTarget->ToCreature());
605 else if (itemTarget)
606 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, itemTarget);
607 }
608
609 void Spell::EffectTriggerSpell(SpellEffIndex /*effIndex*/)
610 {
611 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET
612 && effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
613 return;
614
615 uint32 triggered_spell_id = effectInfo->TriggerSpell;
616
617 /// @todo move those to spell scripts
618 if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL
619 && effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
620 {
621 // special cases
622 switch (triggered_spell_id)
623 {
624 // Vanish (not exist)
625 case 18461:
626 {
627 unitTarget->RemoveMovementImpairingAuras();
628 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
629 return;
630 }
631 // Demonic Empowerment -- succubus
632 case 54437:
633 {
634 unitTarget->RemoveMovementImpairingAuras();
635 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
636 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
637
638 // Cast Lesser Invisibility
639 unitTarget->CastSpell(unitTarget, 7870, true);
640 return;
641 }
642 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
643 case 29284:
644 {
645 // Brittle Armor
646 SpellInfo const* spell = sSpellMgr->GetSpellInfo(24575);
647 if (!spell)
648 return;
649
650 for (uint32 j = 0; j < spell->StackAmount; ++j)
651 m_caster->CastSpell(unitTarget, spell->Id, true);
652 return;
653 }
654 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
655 case 29286:
656 {
657 // Mercurial Shield
658 SpellInfo const* spell = sSpellMgr->GetSpellInfo(26464);
659 if (!spell)
660 return;
661
662 for (uint32 j = 0; j < spell->StackAmount; ++j)
663 m_caster->CastSpell(unitTarget, spell->Id, true);
664 return;
665 }
666 // Cloak of Shadows
667 case 35729:
668 {
669 uint32 dispelMask = SpellInfo::GetDispelMask(DISPEL_ALL);
670 Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
671 for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();)
672 {
673 // remove all harmful spells on you...
674 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
675 if (((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spell->GetSchoolMask() != SPELL_SCHOOL_MASK_NORMAL) // only affect magic spells
676 || (spell->GetDispelMask() & dispelMask)) &&
677 // ignore positive and passive auras
678 !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive())
679 {
680 m_caster->RemoveAura(iter);
681 }
682 else
683 ++iter;
684 }
685 return;
686 }
687 }
688 }
689
690 // normal case
691 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
692 if (!spellInfo)
693 {
694 TC_LOG_ERROR("spells.effecttriggerspell", "Spell::EffectTriggerSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id);
695 return;
696 }
697
698 SpellCastTargets targets;
699 if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
700 {
701 if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()))
702 return;
703 targets.SetUnitTarget(unitTarget);
704 }
705 else //if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH)
706 {
707 if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK))
708 return;
709
710 if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
711 targets.SetDst(m_targets);
712
713 if (Unit* target = m_targets.GetUnitTarget())
714 targets.SetUnitTarget(target);
715 else
716 targets.SetUnitTarget(m_caster);
717 }
718
719 CustomSpellValues values;
720 // set basepoints for trigger with value effect
721 if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE)
722 {
723 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
724 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
725 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
726 }
727
728 // original caster guid only for GO cast
729 m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
730 }
731
732 void Spell::EffectTriggerMissileSpell(SpellEffIndex /*effIndex*/)
733 {
734 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET
735 && effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
736 return;
737
738 uint32 triggered_spell_id = effectInfo->TriggerSpell;
739
740 // normal case
741 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
742 if (!spellInfo)
743 {
744 TC_LOG_ERROR("spells.effecttrigermissilespell", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u.", m_spellInfo->Id, triggered_spell_id);
745 return;
746 }
747
748 SpellCastTargets targets;
749 if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
750 {
751 if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()))
752 return;
753 targets.SetUnitTarget(unitTarget);
754 }
755 else //if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT)
756 {
757 if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo, m_caster->GetMap()->GetDifficultyID()) && (effectInfo->GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK))
758 return;
759
760 if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
761 targets.SetDst(m_targets);
762
763 targets.SetUnitTarget(m_caster);
764 }
765
766 CustomSpellValues values;
767 // set basepoints for trigger with value effect
768 if (effectInfo->Effect == SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE)
769 {
770 // maybe need to set value only when basepoints == 0?
771 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
772 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
773 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
774 }
775
776 // original caster guid only for GO cast
777 m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
778 }
779
780 void Spell::EffectForceCast(SpellEffIndex /*effIndex*/)
781 {
782 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
783 return;
784
785 if (!unitTarget)
786 return;
787
788 uint32 triggered_spell_id = effectInfo->TriggerSpell;
789
790 // normal case
791 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
792
793 if (!spellInfo)
794 {
795 TC_LOG_ERROR("spells", "Spell::EffectForceCast of spell %u: triggering unknown spell id %i.", m_spellInfo->Id, triggered_spell_id);
796 return;
797 }
798
799 if (effectInfo->Effect == SPELL_EFFECT_FORCE_CAST && damage)
800 {
801 switch (m_spellInfo->Id)
802 {
803 case 52588: // Skeletal Gryphon Escape
804 case 48598: // Ride Flamebringer Cue
805 unitTarget->RemoveAura(damage);
806 break;
807 case 52463: // Hide In Mine Car
808 case 52349: // Overtake
809 unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
810 return;
811 }
812 }
813
814 switch (spellInfo->Id)
815 {
816 case 72298: // Malleable Goo Summon
817 unitTarget->CastSpell(unitTarget, spellInfo->Id, true, NULL, NULL, m_originalCasterGUID);
818 return;
819 }
820
821 CustomSpellValues values;
822 // set basepoints for trigger with value effect
823 if (effectInfo->Effect == SPELL_EFFECT_FORCE_CAST_WITH_VALUE)
824 {
825 // maybe need to set value only when basepoints == 0?
826 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
827 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
828 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
829 }
830
831 SpellCastTargets targets;
832 targets.SetUnitTarget(m_caster);
833
834 unitTarget->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK);
835 }
836
837 void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex /*effIndex*/)
838 {
839 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
840 return;
841
842 uint32 triggered_spell_id = effectInfo->TriggerSpell;
843 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
844
845 if (!spellInfo)
846 {
847 TC_LOG_ERROR("spells", "EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i.", m_spellInfo->Id, triggered_spell_id);
848 return;
849 }
850
851 finish();
852
853 m_caster->CastSpell((Unit*)NULL, spellInfo, false);
854 }
855
856 void Spell::EffectJump(SpellEffIndex /*effIndex*/)
857 {
858 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
859 return;
860
861 if (m_caster->IsInFlight())
862 return;
863
864 if (!unitTarget)
865 return;
866
867 float x, y, z;
868 unitTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE);
869
870 float speedXY, speedZ;
871 CalculateJumpSpeeds(effectInfo, m_caster->GetExactDist2d(x, y), speedXY, speedZ);
872 JumpArrivalCastArgs arrivalCast;
873 arrivalCast.SpellId = effectInfo->TriggerSpell;
874 arrivalCast.Target = unitTarget->GetGUID();
875 m_caster->GetMotionMaster()->MoveJump(x, y, z, 0.0f, speedXY, speedZ, EVENT_JUMP, false, &arrivalCast);
876 }
877
878 void Spell::EffectJumpDest(SpellEffIndex /*effIndex*/)
879 {
880 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
881 return;
882
883 if (m_caster->IsInFlight())
884 return;
885
886 if (!m_targets.HasDst())
887 return;
888
889 float speedXY, speedZ;
890 CalculateJumpSpeeds(effectInfo, m_caster->GetExactDist2d(destTarget), speedXY, speedZ);
891 JumpArrivalCastArgs arrivalCast;
892 arrivalCast.SpellId = effectInfo->TriggerSpell;
893 m_caster->GetMotionMaster()->MoveJump(*destTarget, speedXY, speedZ, EVENT_JUMP, !m_targets.GetObjectTargetGUID().IsEmpty(), &arrivalCast);
894 }
895
896 void Spell::CalculateJumpSpeeds(SpellEffectInfo const* effInfo, float dist, float& speedXY, float& speedZ)
897 {
898 if (effInfo->MiscValue)
899 speedZ = float(effInfo->MiscValue) / 10;
900 else if (effInfo->MiscValueB)
901 speedZ = float(effInfo->MiscValueB) / 10;
902 else
903 speedZ = 10.0f;
904
905 speedXY = dist * 10.0f / speedZ;
906 }
907
908 void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
909 {
910 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
911 return;
912
913 if (!unitTarget || unitTarget->IsInFlight())
914 return;
915
916 // If not exist data for dest location - return
917 if (!m_targets.HasDst())
918 {
919 TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - does not have a destination for spellId %u.", m_spellInfo->Id);
920 return;
921 }
922
923 // Init dest coordinates
924 uint32 mapid = destTarget->GetMapId();
925 if (mapid == MAPID_INVALID)
926 mapid = unitTarget->GetMapId();
927 float x, y, z, orientation;
928 destTarget->GetPosition(x, y, z, orientation);
929 if (!orientation && m_targets.GetUnitTarget())
930 orientation = m_targets.GetUnitTarget()->GetOrientation();
931 TC_LOG_DEBUG("spells", "Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation);
932
933 if (Player* player = unitTarget->ToPlayer())
934 {
935 // Custom loading screen
936 if (uint32 customLoadingScreenId = effectInfo->MiscValue)
937 player->SendDirectMessage(WorldPackets::Spells::CustomLoadScreen(m_spellInfo->Id, customLoadingScreenId).Write());
938
939 player->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL | TELE_TO_NOT_LEAVE_COMBAT : 0);
940 }
941 else if (mapid == unitTarget->GetMapId())
942 unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
943 else
944 {
945 TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - spellId %u attempted to teleport creature to a different map.", m_spellInfo->Id);
946 return;
947 }
948
949 // post effects for TARGET_DEST_DB
950 switch (m_spellInfo->Id)
951 {
952 // Dimensional Ripper - Everlook
953 case 23442:
954 {
955 int32 r = irand(0, 119);
956 if (r >= 70) // 7/12 success
957 {
958 if (r < 100) // 4/12 evil twin
959 m_caster->CastSpell(m_caster, 23445, true);
960 else // 1/12 fire
961 m_caster->CastSpell(m_caster, 23449, true);
962 }
963 return;
964 }
965 // Ultrasafe Transporter: Toshley's Station
966 case 36941:
967 {
968 if (roll_chance_i(50)) // 50% success
969 {
970 int32 rand_eff = urand(1, 7);
971 switch (rand_eff)
972 {
973 case 1:
974 // soul split - evil
975 m_caster->CastSpell(m_caster, 36900, true);
976 break;
977 case 2:
978 // soul split - good
979 m_caster->CastSpell(m_caster, 36901, true);
980 break;
981 case 3:
982 // Increase the size
983 m_caster->CastSpell(m_caster, 36895, true);
984 break;
985 case 4:
986 // Decrease the size
987 m_caster->CastSpell(m_caster, 36893, true);
988 break;
989 case 5:
990 // Transform
991 {
992 if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
993 m_caster->CastSpell(m_caster, 36897, true);
994 else
995 m_caster->CastSpell(m_caster, 36899, true);
996 break;
997 }
998 case 6:
999 // chicken
1000 m_caster->CastSpell(m_caster, 36940, true);
1001 break;
1002 case 7:
1003 // evil twin
1004 m_caster->CastSpell(m_caster, 23445, true);
1005 break;
1006 }
1007 }
1008 return;
1009 }
1010 // Dimensional Ripper - Area 52
1011 case 36890:
1012 {
1013 if (roll_chance_i(50)) // 50% success
1014 {
1015 int32 rand_eff = urand(1, 4);
1016 switch (rand_eff)
1017 {
1018 case 1:
1019 // soul split - evil
1020 m_caster->CastSpell(m_caster, 36900, true);
1021 break;
1022 case 2:
1023 // soul split - good
1024 m_caster->CastSpell(m_caster, 36901, true);
1025 break;
1026 case 3:
1027 // Increase the size
1028 m_caster->CastSpell(m_caster, 36895, true);
1029 break;
1030 case 4:
1031 // Transform
1032 {
1033 if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
1034 m_caster->CastSpell(m_caster, 36897, true);
1035 else
1036 m_caster->CastSpell(m_caster, 36899, true);
1037 break;
1038 }
1039 }
1040 }
1041 return;
1042 }
1043 }
1044 }
1045
1046 void Spell::EffectApplyAura(SpellEffIndex effIndex)
1047 {
1048 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1049 return;
1050
1051 if (!m_spellAura || !unitTarget)
1052 return;
1053 ASSERT(unitTarget == m_spellAura->GetOwner());
1054 m_spellAura->_ApplyEffectForTargets(effIndex);
1055 }
1056
1057 void Spell::EffectApplyAreaAura(SpellEffIndex effIndex)
1058 {
1059 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1060 return;
1061
1062 if (!m_spellAura || !unitTarget)
1063 return;
1064 ASSERT (unitTarget == m_spellAura->GetOwner());
1065 m_spellAura->_ApplyEffectForTargets(effIndex);
1066 }
1067
1068 void Spell::EffectUnlearnSpecialization(SpellEffIndex /*effIndex*/)
1069 {
1070 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1071 return;
1072
1073 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1074 return;
1075
1076 Player* player = unitTarget->ToPlayer();
1077 uint32 spellToUnlearn = effectInfo->TriggerSpell;
1078
1079 player->RemoveSpell(spellToUnlearn);
1080
1081 TC_LOG_DEBUG("spells", "Spell: %s has unlearned spell %u from %s", player->GetGUID().ToString().c_str(), spellToUnlearn, m_caster->GetGUID().ToString().c_str());
1082 }
1083
1084 void Spell::EffectPowerDrain(SpellEffIndex effIndex)
1085 {
1086 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1087 return;
1088
1089 if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS))
1090 return;
1091
1092 Powers powerType = Powers(effectInfo->MiscValue);
1093
1094 if (!unitTarget || !unitTarget->IsAlive() || unitTarget->GetPowerType() != powerType || damage < 0)
1095 return;
1096
1097 // add spell damage bonus
1098 uint32 bonus = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo);
1099 damage = bonus + uint32(bonus * variance);
1100 damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effectInfo);
1101
1102 int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage));
1103
1104 float gainMultiplier = 0.0f;
1105
1106 // Don't restore from self drain
1107 if (m_caster != unitTarget)
1108 {
1109 gainMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this);
1110
1111 int32 gain = int32(newDamage* gainMultiplier);
1112
1113 m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, powerType);
1114 }
1115 ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, gainMultiplier);
1116 }
1117
1118 void Spell::EffectSendEvent(SpellEffIndex /*effIndex*/)
1119 {
1120 // we do not handle a flag dropping or clicking on flag in battleground by sendevent system
1121 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET
1122 && effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1123 return;
1124
1125 WorldObject* target = NULL;
1126
1127 // call events for object target if present
1128 if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
1129 {
1130 if (unitTarget)
1131 target = unitTarget;
1132 else if (gameObjTarget)
1133 target = gameObjTarget;
1134 }
1135 else // if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT)
1136 {
1137 // let's prevent executing effect handler twice in case when spell effect is capable of targeting an object
1138 // this check was requested by scripters, but it has some downsides:
1139 // now it's impossible to script (using sEventScripts) a cast which misses all targets
1140 // or to have an ability to script the moment spell hits dest (in a case when there are object targets present)
1141 if (effectInfo->GetProvidedTargetMask() & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
1142 return;
1143 // some spells have no target entries in dbc and they use focus target
1144 if (focusObject)
1145 target = focusObject;
1146 /// @todo there should be a possibility to pass dest target to event script
1147 }
1148
1149 TC_LOG_DEBUG("spells", "Spell ScriptStart %u for spellid %u in EffectSendEvent ", effectInfo->MiscValue, m_spellInfo->Id);
1150
1151 if (ZoneScript* zoneScript = m_caster->GetZoneScript())
1152 zoneScript->ProcessEvent(target, effectInfo->MiscValue);
1153 else if (InstanceScript* instanceScript = m_caster->GetInstanceScript()) // needed in case Player is the caster
1154 instanceScript->ProcessEvent(target, effectInfo->MiscValue);
1155
1156 m_caster->GetMap()->ScriptsStart(sEventScripts, effectInfo->MiscValue, m_caster, target);
1157 }
1158
1159 void Spell::EffectPowerBurn(SpellEffIndex effIndex)
1160 {
1161 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1162 return;
1163
1164 if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS))
1165 return;
1166
1167 Powers powerType = Powers(effectInfo->MiscValue);
1168
1169 if (!unitTarget || !unitTarget->IsAlive() || unitTarget->GetPowerType() != powerType || damage < 0)
1170 return;
1171
1172 int32 newDamage = -(unitTarget->ModifyPower(powerType, -damage));
1173
1174 // NO - Not a typo - EffectPowerBurn uses effect value multiplier - not effect damage multiplier
1175 float dmgMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this);
1176
1177 // add log data before multiplication (need power amount, not damage)
1178 ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, 0.0f);
1179
1180 newDamage = int32(newDamage* dmgMultiplier);
1181
1182 m_damage += newDamage;
1183 }
1184
1185 void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
1186 {
1187 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
1188 return;
1189
1190 if (unitTarget && unitTarget->IsAlive() && damage >= 0)
1191 {
1192 // Try to get original caster
1193 Unit* caster = !m_originalCasterGUID.IsEmpty() ? m_originalCaster : m_caster;
1194
1195 // Skip if m_originalCaster not available
1196 if (!caster)
1197 return;
1198
1199 int32 addhealth = damage;
1200
1201 // Vessel of the Naaru (Vial of the Sunwell trinket)
1202 if (m_spellInfo->Id == 45064)
1203 {
1204 // Amount of heal - depends from stacked Holy Energy
1205 int damageAmount = 0;
1206 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(45062, 0))
1207 {
1208 damageAmount+= aurEff->GetAmount();
1209 m_caster->RemoveAurasDueToSpell(45062);
1210 }
1211
1212 addhealth += damageAmount;
1213 }
1214 // Runic Healing Injector (heal increased by 25% for engineers - 3.2.0 patch change)
1215 else if (m_spellInfo->Id == 67489)
1216 {
1217 if (Player* player = m_caster->ToPlayer())
1218 if (player->HasSkill(SKILL_ENGINEERING))
1219 AddPct(addhealth, 25);
1220 }
1221 // Death Pact - return pct of max health to caster
1222 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
1223 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL, effectInfo);
1224 else
1225 {
1226 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, effectInfo);
1227 uint32 bonus = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL, effectInfo);
1228 damage = bonus + uint32(bonus * variance);
1229 }
1230
1231 addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL, effectInfo);
1232
1233 // Remove Grievious bite if fully healed
1234 if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth()))
1235 unitTarget->RemoveAura(48920);
1236
1237 m_damage -= addhealth;
1238 }
1239 }
1240
1241 void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
1242 {
1243 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1244 return;
1245
1246 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1247 return;
1248
1249 // Skip if m_originalCaster not available
1250 if (!m_originalCaster)
1251 return;
1252
1253 uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL, effectInfo);
1254 heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL, effectInfo);
1255
1256 m_healing += heal;
1257 }
1258
1259 void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
1260 {
1261 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1262 return;
1263
1264 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1265 return;
1266
1267 // Skip if m_originalCaster not available
1268 if (!m_originalCaster)
1269 return;
1270
1271 uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL, effectInfo);
1272 heal += uint32(heal * variance);
1273
1274 m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL, effectInfo);
1275 }
1276
1277 void Spell::EffectHealthLeech(SpellEffIndex /*effIndex*/)
1278 {
1279 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1280 return;
1281
1282 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1283 return;
1284
1285 uint32 bonus = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE, effectInfo);
1286 damage = bonus + uint32(bonus * variance);
1287 damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE, effectInfo);
1288
1289 TC_LOG_DEBUG("spells", "HealthLeech :%i", damage);
1290
1291 float healMultiplier = effectInfo->CalcValueMultiplier(m_originalCaster, this);
1292
1293 m_damage += damage;
1294 // get max possible damage, don't count overkill for heal
1295 uint32 healthGain = uint32(-unitTarget->GetHealthGain(-damage) * healMultiplier);
1296
1297 if (m_caster->IsAlive())
1298 {
1299 healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL, effectInfo);
1300 healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL, effectInfo);
1301
1302 HealInfo healInfo(m_caster, m_caster, healthGain, m_spellInfo, m_spellSchoolMask);
1303 m_caster->HealBySpell(healInfo);
1304 }
1305 }
1306
1307 void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype, uint8 context /*= 0*/, std::vector<int32> const& bonusListIDs /*= std::vector<int32>()*/)
1308 {
1309 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1310 return;
1311
1312 Player* player = unitTarget->ToPlayer();
1313
1314 uint32 newitemid = itemtype;
1315 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(newitemid);
1316 if (!pProto)
1317 {
1318 player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
1319 return;
1320 }
1321
1322 // bg reward have some special in code work
1323 uint32 bgType = 0;
1324 switch (m_spellInfo->Id)
1325 {
1326 case SPELL_AV_MARK_WINNER:
1327 case SPELL_AV_MARK_LOSER:
1328 bgType = BATTLEGROUND_AV;
1329 break;
1330 case SPELL_WS_MARK_WINNER:
1331 case SPELL_WS_MARK_LOSER:
1332 bgType = BATTLEGROUND_WS;
1333 break;
1334 case SPELL_AB_MARK_WINNER:
1335 case SPELL_AB_MARK_LOSER:
1336 bgType = BATTLEGROUND_AB;
1337 break;
1338 default:
1339 break;
1340 }
1341
1342 uint32 num_to_add = damage;
1343
1344 if (num_to_add < 1)
1345 num_to_add = 1;
1346 if (num_to_add > pProto->GetMaxStackSize())
1347 num_to_add = pProto->GetMaxStackSize();
1348
1349 /* == gem perfection handling == */
1350 // this is bad, should be done using spell_loot_template (and conditions)
1351
1352 // the chance of getting a perfect result
1353 float perfectCreateChance = 0.0f;
1354 // the resulting perfect item if successful
1355 uint32 perfectItemType = itemtype;
1356 // get perfection capability and chance
1357 if (CanCreatePerfectItem(player, m_spellInfo->Id, perfectCreateChance, perfectItemType))
1358 if (roll_chance_f(perfectCreateChance)) // if the roll succeeds...
1359 newitemid = perfectItemType; // the perfect item replaces the regular one
1360
1361 /* == gem perfection handling over == */
1362
1363
1364 /* == profession specialization handling == */
1365
1366 // init items_count to 1, since 1 item will be created regardless of specialization
1367 int items_count=1;
1368 // the chance to create additional items
1369 float additionalCreateChance=0.0f;
1370 // the maximum number of created additional items
1371 uint8 additionalMaxNum=0;
1372 // get the chance and maximum number for creating extra items
1373 if (CanCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum))
1374 // roll with this chance till we roll not to create or we create the max num
1375 while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum)
1376 ++items_count;
1377
1378 // really will be created more items
1379 num_to_add *= items_count;
1380
1381 /* == profession specialization handling over == */
1382
1383
1384 // can the player store the new item?
1385 ItemPosCountVec dest;
1386 uint32 no_space = 0;
1387 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space);
1388 if (msg != EQUIP_ERR_OK)
1389 {
1390 // convert to possible store amount
1391 if (msg == EQUIP_ERR_INV_FULL || msg == EQUIP_ERR_ITEM_MAX_COUNT)
1392 num_to_add -= no_space;
1393 else
1394 {
1395 // if not created by another reason from full inventory or unique items amount limitation
1396 player->SendEquipError(msg, NULL, NULL, newitemid);
1397 return;
1398 }
1399 }
1400
1401 if (num_to_add)
1402 {
1403 // create the new item and store it
1404 Item* pItem = player->StoreNewItem(dest, newitemid, true, GenerateItemRandomPropertyId(newitemid), GuidSet(), context, bonusListIDs);
1405
1406 // was it successful? return error if not
1407 if (!pItem)
1408 {
1409 player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
1410 return;
1411 }
1412
1413 // set the "Crafted by ..." property of the item
1414 if (pItem->GetTemplate()->GetClass() != ITEM_CLASS_CONSUMABLE && pItem->GetTemplate()->GetClass() != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
1415 pItem->SetGuidValue(ITEM_FIELD_CREATOR, player->GetGUID());
1416
1417 // send info to the client
1418 player->SendNewItem(pItem, num_to_add, true, bgType == 0);
1419
1420 if (pItem->GetQuality() > ITEM_QUALITY_EPIC || (pItem->GetQuality() == ITEM_QUALITY_EPIC && pItem->GetItemLevel(player) >= MinNewsItemLevel))
1421 if (Guild* guild = player->GetGuild())
1422 guild->AddGuildNews(GUILD_NEWS_ITEM_CRAFTED, player->GetGUID(), 0, pProto->GetId());
1423
1424
1425 // we succeeded in creating at least one item, so a levelup is possible
1426 if (bgType == 0)
1427 player->UpdateCraftSkill(m_spellInfo->Id);
1428 }
1429
1430 /*
1431 // for battleground marks send by mail if not add all expected
1432 if (no_space > 0 && bgType)
1433 {
1434 if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BattlegroundTypeId(bgType)))
1435 bg->SendRewardMarkByMail(player, newitemid, no_space);
1436 }
1437 */
1438 }
1439
1440 void Spell::EffectCreateItem(SpellEffIndex effIndex)
1441 {
1442 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1443 return;
1444
1445 DoCreateItem(effIndex, effectInfo->ItemType);
1446 ExecuteLogEffectCreateItem(effIndex, effectInfo->ItemType);
1447 }
1448
1449 void Spell::EffectCreateItem2(SpellEffIndex effIndex)
1450 {
1451 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1452 return;
1453
1454 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1455 return;
1456
1457 Player* player = unitTarget->ToPlayer();
1458
1459 uint32 item_id = effectInfo->ItemType;
1460
1461 if (item_id)
1462 DoCreateItem(effIndex, item_id);
1463
1464 // special case: fake item replaced by generate using spell_loot_template
1465 if (m_spellInfo->IsLootCrafting())
1466 {
1467 if (item_id)
1468 {
1469 if (!player->HasItemCount(item_id))
1470 return;
1471
1472 // remove reagent
1473 uint32 count = 1;
1474 player->DestroyItemCount(item_id, count, true);
1475
1476 // create some random items
1477 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
1478 }
1479 else
1480 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items
1481
1482 player->UpdateCraftSkill(m_spellInfo->Id);
1483 }
1484 /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType);
1485 }
1486
1487 void Spell::EffectCreateRandomItem(SpellEffIndex /*effIndex*/)
1488 {
1489 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1490 return;
1491
1492 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1493 return;
1494 Player* player = unitTarget->ToPlayer();
1495
1496 // create some random items
1497 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
1498 /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType);
1499 }
1500
1501 void Spell::EffectPersistentAA(SpellEffIndex effIndex)
1502 {
1503 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1504 return;
1505
1506 if (!m_spellAura)
1507 {
1508 Unit* caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster;
1509 float radius = effectInfo->CalcRadius(caster);
1510
1511 // Caster not in world, might be spell triggered from aura removal
1512 if (!caster->IsInWorld())
1513 return;
1514 DynamicObject* dynObj = new DynamicObject(false);
1515 if (!dynObj->CreateDynamicObject(caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL, m_SpellVisual))
1516 {
1517 delete dynObj;
1518 return;
1519 }
1520
1521 if (Aura* aura = Aura::TryCreate(m_spellInfo, m_castId, MAX_EFFECT_MASK, dynObj, caster, &m_spellValue->EffectBasePoints[0], nullptr, ObjectGuid::Empty, ObjectGuid::Empty, m_castItemLevel))
1522 {
1523 m_spellAura = aura;
1524 m_spellAura->_RegisterForTargets();
1525 }
1526 else
1527 return;
1528 }
1529
1530 ASSERT(m_spellAura->GetDynobjOwner());
1531 m_spellAura->_ApplyEffectForTargets(effIndex);
1532 }
1533
1534 void Spell::EffectEnergize(SpellEffIndex /*effIndex*/)
1535 {
1536 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1537 return;
1538
1539 if (!unitTarget)
1540 return;
1541 if (!unitTarget->IsAlive())
1542 return;
1543
1544 if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS))
1545 return;
1546
1547 Powers power = Powers(effectInfo->MiscValue);
1548
1549 if (unitTarget->GetMaxPower(power) == 0)
1550 return;
1551
1552 // Some level depends spells
1553 switch (m_spellInfo->Id)
1554 {
1555 case 24571: // Blood Fury
1556 // Instantly increases your rage by ${(300-10*$max(0,$PL-60))/10}.
1557 damage -= 10 * std::max(0, std::min(30, m_caster->getLevel() - 60));
1558 break;
1559 case 24532: // Burst of Energy
1560 // Instantly increases your energy by ${60-4*$max(0,$min(15,$PL-60))}.
1561 damage -= 4 * std::max(0, std::min(15, m_caster->getLevel() - 60));
1562 break;
1563 case 67490: // Runic Mana Injector (mana gain increased by 25% for engineers - 3.2.0 patch change)
1564 {
1565 if (Player* player = m_caster->ToPlayer())
1566 if (player->HasSkill(SKILL_ENGINEERING))
1567 AddPct(damage, 25);
1568 break;
1569 }
1570 default:
1571 break;
1572 }
1573
1574 m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
1575
1576 // Mad Alchemist's Potion
1577 if (m_spellInfo->Id == 45051)
1578 {
1579 // find elixirs on target
1580 bool guardianFound = false;
1581 bool battleFound = false;
1582 Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
1583 for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
1584 {
1585 uint32 spell_id = itr->second->GetBase()->GetId();
1586 if (!guardianFound)
1587 if (sSpellMgr->IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_GUARDIAN))
1588 guardianFound = true;
1589 if (!battleFound)
1590 if (sSpellMgr->IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_BATTLE))
1591 battleFound = true;
1592 if (battleFound && guardianFound)
1593 break;
1594 }
1595
1596 // get all available elixirs by mask and spell level
1597 std::set<uint32> avalibleElixirs;
1598 if (!guardianFound)
1599 sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, avalibleElixirs);
1600 if (!battleFound)
1601 sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs);
1602 for (std::set<uint32>::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end();)
1603 {
1604 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*itr);
1605 if (spellInfo->SpellLevel < m_spellInfo->SpellLevel || spellInfo->SpellLevel > unitTarget->getLevel())
1606 avalibleElixirs.erase(itr++);
1607 else if (sSpellMgr->IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH))
1608 avalibleElixirs.erase(itr++);
1609 else if (sSpellMgr->IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_UNSTABLE))
1610 avalibleElixirs.erase(itr++);
1611 else
1612 ++itr;
1613 }
1614
1615 if (!avalibleElixirs.empty())
1616 {
1617 // cast random elixir on target
1618 m_caster->CastSpell(unitTarget, Trinity::Containers::SelectRandomContainerElement(avalibleElixirs), true, m_CastItem);
1619 }
1620 }
1621 }
1622
1623 void Spell::EffectEnergizePct(SpellEffIndex /*effIndex*/)
1624 {
1625 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1626 return;
1627
1628 if (!unitTarget)
1629 return;
1630 if (!unitTarget->IsAlive())
1631 return;
1632
1633 if (effectInfo->MiscValue < 0 || effectInfo->MiscValue >= int8(MAX_POWERS))
1634 return;
1635
1636 Powers power = Powers(effectInfo->MiscValue);
1637 uint32 maxPower = unitTarget->GetMaxPower(power);
1638 if (maxPower == 0)
1639 return;
1640
1641 uint32 gain = CalculatePct(maxPower, damage);
1642 m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power);
1643 }
1644
1645 void Spell::SendLoot(ObjectGuid guid, LootType loottype)
1646 {
1647 Player* player = m_caster->ToPlayer();
1648 if (!player)
1649 return;
1650
1651 if (gameObjTarget)
1652 {
1653 // Players shouldn't be able to loot gameobjects that are currently despawned
1654 if (!gameObjTarget->isSpawned() && !player->IsGameMaster())
1655 {
1656 TC_LOG_ERROR("entities.player.cheat", "Possible hacking attempt: Player %s [%s] tried to loot a gameobject [%s] which is on respawn times without being in GM mode!",
1657 player->GetName().c_str(), player->GetGUID().ToString().c_str(), gameObjTarget->GetGUID().ToString().c_str());
1658 return;
1659 }
1660 // special case, already has GossipHello inside so return and avoid calling twice
1661 if (gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_GOOBER)
1662 {
1663 gameObjTarget->Use(m_caster);
1664 return;
1665 }
1666
1667 if (sScriptMgr->OnGossipHello(player, gameObjTarget))
1668 return;
1669
1670 if (gameObjTarget->AI()->GossipHello(player, true))
1671 return;
1672
1673 switch (gameObjTarget->GetGoType())
1674 {
1675 case GAMEOBJECT_TYPE_DOOR:
1676 case GAMEOBJECT_TYPE_BUTTON:
1677 gameObjTarget->UseDoorOrButton(0, false, player);
1678 return;
1679
1680 case GAMEOBJECT_TYPE_QUESTGIVER:
1681 player->PrepareGossipMenu(gameObjTarget, gameObjTarget->GetGOInfo()->questgiver.gossipID, true);
1682 player->SendPreparedGossip(gameObjTarget);
1683 return;
1684
1685 case GAMEOBJECT_TYPE_SPELL_FOCUS:
1686 // triggering linked GO
1687 if (uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrap)
1688 gameObjTarget->TriggeringLinkedGameObject(trapEntry, m_caster);
1689 return;
1690
1691 case GAMEOBJECT_TYPE_CHEST:
1692 /// @todo possible must be moved to loot release (in different from linked triggering)
1693 if (gameObjTarget->GetGOInfo()->chest.triggeredEvent)
1694 {
1695 TC_LOG_DEBUG("spells", "Chest ScriptStart id %u for GO " UI64FMTD, gameObjTarget->GetGOInfo()->chest.triggeredEvent, gameObjTarget->GetSpawnId());
1696 player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.triggeredEvent, player, gameObjTarget);
1697 }
1698
1699 // triggering linked GO
1700 if (uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrap)
1701 gameObjTarget->TriggeringLinkedGameObject(trapEntry, m_caster);
1702
1703 // Don't return, let loots been taken
1704 default:
1705 break;
1706 }
1707 }
1708
1709 // Send loot
1710 player->SendLoot(guid, loottype);
1711 }
1712
1713 void Spell::EffectOpenLock(SpellEffIndex effIndex)
1714 {
1715 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1716 return;
1717
1718 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1719 {
1720 TC_LOG_DEBUG("spells", "WORLD: Open Lock - No Player Caster!");
1721 return;
1722 }
1723
1724 Player* player = m_caster->ToPlayer();
1725
1726 uint32 lockId = 0;
1727 ObjectGuid guid;
1728
1729 // Get lockId
1730 if (gameObjTarget)
1731 {
1732 GameObjectTemplate const* goInfo = gameObjTarget->GetGOInfo();
1733 // Arathi Basin banner opening. /// @todo Verify correctness of this check
1734 if ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) ||
1735 (goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.requireLOS))
1736 {
1737 //CanUseBattlegroundObject() already called in CheckCast()
1738 // in battleground check
1739 if (Battleground* bg = player->GetBattleground())
1740 {
1741 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
1742 return;
1743 }
1744 }
1745 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
1746 {
1747 //CanUseBattlegroundObject() already called in CheckCast()
1748 // in battleground check
1749 if (Battleground* bg = player->GetBattleground())
1750 {
1751 if (bg->GetTypeID(true) == BATTLEGROUND_EY)
1752 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
1753 return;
1754 }
1755 }
1756 else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner())
1757 {
1758 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
1759 return;
1760 }
1761 /// @todo Add script for spell 41920 - Filling, becouse server it freze when use this spell
1762 // handle outdoor pvp object opening, return true if go was registered for handling
1763 // these objects must have been spawned by outdoorpvp!
1764 else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr->HandleOpenGo(player, gameObjTarget))
1765 return;
1766 lockId = goInfo->GetLockId();
1767 guid = gameObjTarget->GetGUID();
1768 }
1769 else if (itemTarget)
1770 {
1771 lockId = itemTarget->GetTemplate()->GetLockID();
1772 guid = itemTarget->GetGUID();
1773 }
1774 else
1775 {
1776 TC_LOG_DEBUG("spells", "WORLD: Open Lock - No GameObject/Item Target!");
1777 return;
1778 }
1779
1780 SkillType skillId = SKILL_NONE;
1781 int32 reqSkillValue = 0;
1782 int32 skillValue;
1783
1784 SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue);
1785 if (res != SPELL_CAST_OK)
1786 {
1787 SendCastResult(res);
1788 return;
1789 }
1790
1791 if (gameObjTarget)
1792 SendLoot(guid, LOOT_SKINNING);
1793 else if (itemTarget)
1794 {
1795 itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED);
1796 itemTarget->SetState(ITEM_CHANGED, itemTarget->GetOwner());
1797 }
1798
1799 // not allow use skill grow at item base open
1800 if (!m_CastItem && skillId != SKILL_NONE)
1801 {
1802 // update skill if really known
1803 if (uint32 pureSkillValue = player->GetPureSkillValue(skillId))
1804 {
1805 if (gameObjTarget)
1806 {
1807 // Allow one skill-up until respawned
1808 if (!gameObjTarget->IsInSkillupList(player->GetGUID()) &&
1809 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue))
1810 gameObjTarget->AddToSkillupList(player->GetGUID());
1811 }
1812 else if (itemTarget)
1813 {
1814 // Do one skill-up
1815 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
1816 }
1817 }
1818 }
1819 ExecuteLogEffectOpenLock(effIndex, gameObjTarget ? (Object*)gameObjTarget : (Object*)itemTarget);
1820 }
1821
1822 void Spell::EffectSummonChangeItem(SpellEffIndex /*effIndex*/)
1823 {
1824 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1825 return;
1826
1827 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1828 return;
1829
1830 Player* player = m_caster->ToPlayer();
1831
1832 // applied only to using item
1833 if (!m_CastItem)
1834 return;
1835
1836 // ... only to item in own inventory/bank/equip_slot
1837 if (m_CastItem->GetOwnerGUID() != player->GetGUID())
1838 return;
1839
1840 uint32 newitemid = effectInfo->ItemType;
1841 if (!newitemid)
1842 return;
1843
1844 uint16 pos = m_CastItem->GetPos();
1845
1846 Item* pNewItem = Item::CreateItem(newitemid, 1, player);
1847 if (!pNewItem)
1848 return;
1849
1850 for (uint8 j = PERM_ENCHANTMENT_SLOT; j <= TEMP_ENCHANTMENT_SLOT; ++j)
1851 if (m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
1852 pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
1853
1854 if (m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
1855 {
1856 double lossPercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
1857 player->DurabilityLoss(pNewItem, lossPercent);
1858 }
1859
1860 if (player->IsInventoryPos(pos))
1861 {
1862 ItemPosCountVec dest;
1863 InventoryResult msg = player->CanStoreItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true);
1864 if (msg == EQUIP_ERR_OK)
1865 {
1866 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
1867
1868 // prevent crash at access and unexpected charges counting with item update queue corrupt
1869 if (m_CastItem == m_targets.GetItemTarget())
1870 m_targets.SetItemTarget(NULL);
1871
1872 m_CastItem = NULL;
1873 m_castItemGUID.Clear();
1874 m_castItemEntry = 0;
1875 m_castItemLevel = -1;
1876
1877 player->StoreItem(dest, pNewItem, true);
1878 player->SendNewItem(pNewItem, 1, true, false);
1879 player->ItemAddedQuestCheck(newitemid, 1);
1880 return;
1881 }
1882 }
1883 else if (player->IsBankPos(pos))
1884 {
1885 ItemPosCountVec dest;
1886 if (player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true) == EQUIP_ERR_OK)
1887 {
1888 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
1889
1890 // prevent crash at access and unexpected charges counting with item update queue corrupt
1891 if (m_CastItem == m_targets.GetItemTarget())
1892 m_targets.SetItemTarget(NULL);
1893
1894 m_CastItem = NULL;
1895 m_castItemGUID.Clear();
1896 m_castItemEntry = 0;
1897 m_castItemLevel = -1;
1898
1899 player->BankItem(dest, pNewItem, true);
1900 return;
1901 }
1902 }
1903 else if (player->IsEquipmentPos(pos))
1904 {
1905 uint16 dest;
1906
1907 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
1908
1909 InventoryResult msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true);
1910
1911 if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CLIENT_LOCKED_OUT)
1912 {
1913 if (msg == EQUIP_ERR_CLIENT_LOCKED_OUT) dest = EQUIPMENT_SLOT_MAINHAND;
1914
1915 // prevent crash at access and unexpected charges counting with item update queue corrupt
1916 if (m_CastItem == m_targets.GetItemTarget())
1917 m_targets.SetItemTarget(NULL);
1918
1919 m_CastItem = NULL;
1920 m_castItemGUID.Clear();
1921 m_castItemEntry = 0;
1922 m_castItemLevel = -1;
1923
1924 player->EquipItem(dest, pNewItem, true);
1925 player->AutoUnequipOffhandIfNeed();
1926 player->SendNewItem(pNewItem, 1, true, false);
1927 player->ItemAddedQuestCheck(newitemid, 1);
1928 return;
1929 }
1930 }
1931
1932 // fail
1933 delete pNewItem;
1934 }
1935
1936 void Spell::EffectProficiency(SpellEffIndex /*effIndex*/)
1937 {
1938 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1939 return;
1940
1941 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1942 return;
1943 Player* p_target = m_caster->ToPlayer();
1944
1945 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
1946 if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & subClassMask))
1947 {
1948 p_target->AddWeaponProficiency(subClassMask);
1949 p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency());
1950 }
1951 if (m_spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & subClassMask))
1952 {
1953 p_target->AddArmorProficiency(subClassMask);
1954 p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency());
1955 }
1956 }
1957
1958 void Spell::EffectSummonType(SpellEffIndex effIndex)
1959 {
1960 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1961 return;
1962
1963 uint32 entry = effectInfo->MiscValue;
1964 if (!entry)
1965 return;
1966
1967 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(effectInfo->MiscValueB);
1968 if (!properties)
1969 {
1970 TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u.", effectInfo->MiscValueB);
1971 return;
1972 }
1973
1974 if (!m_originalCaster)
1975 return;
1976
1977 bool personalSpawn = (properties->Flags & SUMMON_PROP_FLAG_PERSONAL_SPAWN) != 0;
1978
1979 int32 duration = m_spellInfo->CalcDuration(m_originalCaster);
1980
1981 TempSummon* summon = NULL;
1982
1983 // determine how many units should be summoned
1984 uint32 numSummons;
1985
1986 // some spells need to summon many units, for those spells number of summons is stored in effect value
1987 // however so far noone found a generic check to find all of those (there's no related data in summonproperties.dbc
1988 // and in spell attributes, possibly we need to add a table for those)
1989 // so here's a list of MiscValueB values, which is currently most generic check
1990 switch (effectInfo->MiscValueB)
1991 {
1992 case 64:
1993 case 61:
1994 case 1101:
1995 case 66:
1996 case 648:
1997 case 2301:
1998 case 1061:
1999 case 1261:
2000 case 629:
2001 case 181:
2002 case 715:
2003 case 1562:
2004 case 833:
2005 case 1161:
2006 case 713:
2007 numSummons = (damage > 0) ? damage : 1;
2008 break;
2009 default:
2010 numSummons = 1;
2011 break;
2012 }
2013
2014 switch (properties->Control)
2015 {
2016 case SUMMON_CATEGORY_WILD:
2017 case SUMMON_CATEGORY_ALLY:
2018 case SUMMON_CATEGORY_UNK:
2019 if (properties->Flags & 512)
2020 {
2021 SummonGuardian(effIndex, entry, properties, numSummons);
2022 break;
2023 }
2024 switch (properties->Title)
2025 {
2026 case SUMMON_TYPE_PET:
2027 case SUMMON_TYPE_GUARDIAN:
2028 case SUMMON_TYPE_GUARDIAN2:
2029 case SUMMON_TYPE_MINION:
2030 SummonGuardian(effIndex, entry, properties, numSummons);
2031 break;
2032 // Summons a vehicle, but doesn't force anyone to enter it (see SUMMON_CATEGORY_VEHICLE)
2033 case SUMMON_TYPE_VEHICLE:
2034 case SUMMON_TYPE_VEHICLE2:
2035 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2036 break;
2037 case SUMMON_TYPE_LIGHTWELL:
2038 case SUMMON_TYPE_TOTEM:
2039 {
2040 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
2041 if (!summon || !summon->IsTotem())
2042 return;
2043
2044 if (damage) // if not spell info, DB values used
2045 {
2046 summon->SetMaxHealth(damage);
2047 summon->SetHealth(damage);
2048 }
2049 break;
2050 }
2051 case SUMMON_TYPE_MINIPET:
2052 {
2053 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
2054 if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION))
2055 return;
2056
2057 summon->SelectLevel(); // some summoned creaters have different from 1 DB data for level/hp
2058 summon->SetUInt64Value(UNIT_NPC_FLAGS, summon->GetCreatureTemplate()->npcflag);
2059
2060 summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
2061
2062 summon->AI()->EnterEvadeMode();
2063 break;
2064 }
2065 default:
2066 {
2067 float radius = effectInfo->CalcRadius();
2068
2069 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2070
2071 for (uint32 count = 0; count < numSummons; ++count)
2072 {
2073 Position pos;
2074 if (count == 0)
2075 pos = *destTarget;
2076 else
2077 // randomize position for multiple summons
2078 pos = m_caster->GetRandomPoint(*destTarget, radius);
2079
2080 summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration, 0, personalSpawn);
2081 if (!summon)
2082 continue;
2083
2084 if (properties->Control == SUMMON_CATEGORY_ALLY)
2085 {
2086 summon->SetOwnerGUID(m_originalCaster->GetGUID());
2087 summon->setFaction(m_originalCaster->getFaction());
2088 summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
2089 }
2090
2091 ExecuteLogEffectSummonObject(effIndex, summon);
2092 }
2093 return;
2094 }
2095 }//switch
2096 break;
2097 case SUMMON_CATEGORY_PET:
2098 SummonGuardian(effIndex, entry, properties, numSummons);
2099 break;
2100 case SUMMON_CATEGORY_PUPPET:
2101 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id, 0, personalSpawn);
2102 break;
2103 case SUMMON_CATEGORY_VEHICLE:
2104 // Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker
2105 // to cast a ride vehicle spell on the summoned unit.
2106 summon = m_originalCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_caster, m_spellInfo->Id);
2107 if (!summon || !summon->IsVehicle())
2108 return;
2109
2110 // The spell that this effect will trigger. It has SPELL_AURA_CONTROL_VEHICLE
2111 uint32 spellId = VEHICLE_SPELL_RIDE_HARDCODED;
2112 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectInfo->CalcValue());
2113 if (spellInfo && spellInfo->HasAura(m_originalCaster->GetMap()->GetDifficultyID(), SPELL_AURA_CONTROL_VEHICLE))
2114 spellId = spellInfo->Id;
2115
2116 // Hard coded enter vehicle spell
2117 m_originalCaster->CastSpell(summon, spellId, true);
2118
2119 uint32 faction = properties->Faction;
2120 if (!faction)
2121 faction = m_originalCaster->getFaction();
2122
2123 summon->setFaction(faction);
2124 break;
2125 }
2126
2127 if (summon)
2128 {
2129 summon->SetCreatorGUID(m_originalCaster->GetGUID());
2130 ExecuteLogEffectSummonObject(effIndex, summon);
2131 }
2132 }
2133
2134 void Spell::EffectLearnSpell(SpellEffIndex effIndex)
2135 {
2136 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2137 return;
2138
2139 if (!unitTarget)
2140 return;
2141
2142 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2143 {
2144 if (unitTarget->ToPet())
2145 EffectLearnPetSpell(effIndex);
2146 return;
2147 }
2148
2149 Player* player = unitTarget->ToPlayer();
2150
2151 uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : effectInfo->TriggerSpell;
2152 player->LearnSpell(spellToLearn, false);
2153
2154 TC_LOG_DEBUG("spells", "Spell: %s has learned spell %u from %s", player->GetGUID().ToString().c_str(), spellToLearn, m_caster->GetGUID().ToString().c_str());
2155 }
2156
2157 void Spell::EffectDispel(SpellEffIndex effIndex)
2158 {
2159 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2160 return;
2161
2162 if (!unitTarget)
2163 return;
2164
2165 // Create dispel mask by dispel type
2166 uint32 dispel_type = effectInfo->MiscValue;
2167 uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(dispel_type));
2168
2169 DispelChargesList dispel_list;
2170 unitTarget->GetDispellableAuraList(m_caster, dispelMask, dispel_list);
2171 if (dispel_list.empty())
2172 return;
2173
2174 // Ok if exist some buffs for dispel try dispel it
2175 DispelChargesList success_list;
2176 WorldPackets::Spells::DispelFailed dispelFailed;
2177 dispelFailed.CasterGUID = m_caster->GetGUID();
2178 dispelFailed.VictimGUID = unitTarget->GetGUID();
2179 dispelFailed.SpellID = m_spellInfo->Id;
2180
2181 // dispel N = damage buffs (or while exist buffs for dispel)
2182 for (int32 count = 0; count < damage && !dispel_list.empty();)
2183 {
2184 // Random select buff for dispel
2185 DispelChargesList::iterator itr = dispel_list.begin();
2186 std::advance(itr, urand(0, dispel_list.size() - 1));
2187
2188 int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
2189 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
2190 if (!chance)
2191 {
2192 dispel_list.erase(itr);
2193 continue;
2194 }
2195 else
2196 {
2197 if (roll_chance_i(chance))
2198 {
2199 bool alreadyListed = false;
2200 for (DispelChargesList::iterator successItr = success_list.begin(); successItr != success_list.end(); ++successItr)
2201 {
2202 if (successItr->first->GetId() == itr->first->GetId())
2203 {
2204 ++successItr->second;
2205 alreadyListed = true;
2206 }
2207 }
2208 if (!alreadyListed)
2209 success_list.push_back(std::make_pair(itr->first, 1));
2210 --itr->second;
2211 if (itr->second <= 0)
2212 dispel_list.erase(itr);
2213 }
2214 else
2215 dispelFailed.FailedSpells.push_back(int32(itr->first->GetId()));
2216
2217 ++count;
2218 }
2219 }
2220
2221 if (!dispelFailed.FailedSpells.empty())
2222 m_caster->SendMessageToSet(dispelFailed.Write(), true);
2223
2224 if (success_list.empty())
2225 return;
2226
2227 WorldPackets::CombatLog::SpellDispellLog spellDispellLog;
2228 spellDispellLog.IsBreak = false; // TODO: use me
2229 spellDispellLog.IsSteal = false;
2230
2231 spellDispellLog.TargetGUID = unitTarget->GetGUID();
2232 spellDispellLog.CasterGUID = m_caster->GetGUID();
2233 spellDispellLog.DispelledBySpellID = m_spellInfo->Id;
2234
2235 for (std::pair<Aura*, uint8> const& dispellCharge : success_list)
2236 {
2237 WorldPackets::CombatLog::SpellDispellData dispellData;
2238 dispellData.SpellID = dispellCharge.first->GetId();
2239 dispellData.Harmful = false; // TODO: use me
2240 dispellData.Rolled = boost::none; // TODO: use me
2241 dispellData.Needed = boost::none; // TODO: use me
2242
2243 unitTarget->RemoveAurasDueToSpellByDispel(dispellCharge.first->GetId(), m_spellInfo->Id, dispellCharge.first->GetCasterGUID(), m_caster, dispellCharge.second);
2244
2245 spellDispellLog.DispellData.emplace_back(dispellData);
2246 }
2247
2248 m_caster->SendMessageToSet(spellDispellLog.Write(), true);
2249
2250 CallScriptSuccessfulDispel(effIndex);
2251 }
2252
2253 void Spell::EffectDualWield(SpellEffIndex /*effIndex*/)
2254 {
2255 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2256 return;
2257
2258 unitTarget->SetCanDualWield(true);
2259 }
2260
2261 void Spell::EffectPull(SpellEffIndex effIndex)
2262 {
2263 /// @todo create a proper pull towards distract spell center for distract
2264 EffectNULL(effIndex);
2265 }
2266
2267 void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
2268 {
2269 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2270 return;
2271
2272 // Check for possible target
2273 if (!unitTarget || unitTarget->IsInCombat())
2274 return;
2275
2276 // target must be OK to do this
2277 if (unitTarget->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING))
2278 return;
2279
2280 unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
2281 unitTarget->ClearUnitState(UNIT_STATE_MOVING);
2282
2283 if (unitTarget->GetTypeId() == TYPEID_UNIT)
2284 unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
2285 }
2286
2287 void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
2288 {
2289 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2290 return;
2291
2292 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2293 return;
2294
2295 // victim must be creature and attackable
2296 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget))
2297 return;
2298
2299 // victim have to be alive and humanoid or undead
2300 if (unitTarget->IsAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
2301 m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(), LOOT_PICKPOCKETING);
2302 }
2303
2304 void Spell::EffectAddFarsight(SpellEffIndex /*effIndex*/)
2305 {
2306 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2307 return;
2308
2309 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2310 return;
2311
2312 float radius = effectInfo->CalcRadius();
2313 int32 duration = m_spellInfo->CalcDuration(m_caster);
2314 // Caster not in world, might be spell triggered from aura removal
2315 if (!m_caster->IsInWorld())
2316 return;
2317
2318 DynamicObject* dynObj = new DynamicObject(true);
2319 if (!dynObj->CreateDynamicObject(m_caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), m_caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS, m_SpellVisual))
2320 {
2321 delete dynObj;
2322 return;
2323 }
2324
2325 dynObj->SetDuration(duration);
2326 dynObj->SetCasterViewpoint();
2327 }
2328
2329 void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)
2330 {
2331 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2332 return;
2333
2334 if (!unitTarget || m_caster->GetTypeId() == TYPEID_PLAYER)
2335 return;
2336
2337 unitTarget->ToPlayer()->SendRespecWipeConfirm(m_caster->GetGUID(), sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : unitTarget->ToPlayer()->GetNextResetTalentsCost());
2338 }
2339
2340 void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex /*effIndex*/)
2341 {
2342 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2343 return;
2344
2345 if (!unitTarget)
2346 return;
2347
2348 if (unitTarget->IsInFlight())
2349 return;
2350
2351 float dis = effectInfo->CalcRadius(m_caster);
2352
2353 float fx, fy, fz;
2354 m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis);
2355
2356 unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
2357 }
2358
2359 void Spell::EffectLearnSkill(SpellEffIndex /*effIndex*/)
2360 {
2361 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2362 return;
2363
2364 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2365 return;
2366
2367 if (damage < 0)
2368 return;
2369
2370 uint32 skillid = effectInfo->MiscValue;
2371 SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass());
2372 if (!rcEntry)
2373 return;
2374
2375 SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcEntry->SkillTierID);
2376 if (!tier)
2377 return;
2378
2379 uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid);
2380 unitTarget->ToPlayer()->SetSkill(skillid, effectInfo->CalcValue(), std::max<uint16>(skillval, 1), tier->Value[damage - 1]);
2381 }
2382
2383 void Spell::EffectPlayMovie(SpellEffIndex /*effIndex*/)
2384 {
2385 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2386 return;
2387
2388 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2389 return;
2390
2391 uint32 movieId = effectInfo->MiscValue;
2392 if (!sMovieStore.LookupEntry(movieId))
2393 return;
2394
2395 unitTarget->ToPlayer()->SendMovieStart(movieId);
2396 }
2397
2398 void Spell::EffectTradeSkill(SpellEffIndex /*effIndex*/)
2399 {
2400 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2401 return;
2402
2403 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2404 return;
2405 // uint32 skillid = m_spellInfo->Effects[i].MiscValue;
2406 // uint16 skillmax = unitTarget->ToPlayer()->(skillid);
2407 // m_caster->ToPlayer()->SetSkill(skillid, skillval?skillval:1, skillmax+75);
2408 }
2409
2410 void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
2411 {
2412 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2413 return;
2414
2415 if (!itemTarget)
2416 return;
2417
2418 Player* player = m_caster->ToPlayer();
2419 if (!player)
2420 return;
2421
2422 // Handle vellums
2423 if (itemTarget->IsVellum())
2424 {
2425 // destroy one vellum from stack
2426 uint32 count = 1;
2427 player->DestroyItemCount(itemTarget, count, true);
2428 unitTarget = player;
2429 // and add a scroll
2430 DoCreateItem(effIndex, effectInfo->ItemType);
2431 itemTarget = NULL;
2432 m_targets.SetItemTarget(NULL);
2433 }
2434 else
2435 {
2436 // do not increase skill if vellum used
2437 if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST))
2438 player->UpdateCraftSkill(m_spellInfo->Id);
2439
2440 uint32 enchant_id = effectInfo->MiscValue;
2441 if (!enchant_id)
2442 return;
2443
2444 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2445 if (!pEnchant)
2446 return;
2447
2448 // item can be in trade slot and have owner diff. from caster
2449 Player* item_owner = itemTarget->GetOwner();
2450 if (!item_owner)
2451 return;
2452
2453 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2454 {
2455 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2456 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2457 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2458 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2459 }
2460
2461 // remove old enchanting before applying new if equipped
2462 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, false);
2463
2464 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0, m_caster->GetGUID());
2465
2466 // add new enchanting if equipped
2467 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, true);
2468
2469 item_owner->RemoveTradeableItem(itemTarget);
2470 itemTarget->ClearSoulboundTradeable(item_owner);
2471 }
2472 }
2473
2474 void Spell::EffectEnchantItemPrismatic(SpellEffIndex /*effIndex*/)
2475 {
2476 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2477 return;
2478
2479 if (!itemTarget)
2480 return;
2481
2482 Player* player = m_caster->ToPlayer();
2483 if (!player)
2484 return;
2485
2486 uint32 enchantId = effectInfo->MiscValue;
2487 if (!enchantId)
2488 return;
2489
2490 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2491 if (!enchant)
2492 return;
2493
2494 // support only enchantings with add socket in this slot
2495 {
2496 bool add_socket = false;
2497 for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
2498 {
2499 if (enchant->Effect[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
2500 {
2501 add_socket = true;
2502 break;
2503 }
2504 }
2505 if (!add_socket)
2506 {
2507 TC_LOG_ERROR("spells", "Spell::EffectEnchantItemPrismatic: attempt to apply the enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u), but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not supported yet.",
2508 m_spellInfo->Id, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC, ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
2509 return;
2510 }
2511 }
2512
2513 // item can be in trade slot and have owner diff. from caster
2514 Player* item_owner = itemTarget->GetOwner();
2515 if (!item_owner)
2516 return;
2517
2518 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2519 {
2520 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2521 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2522 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2523 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2524 }
2525
2526 // remove old enchanting before applying new if equipped
2527 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, false);
2528
2529 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchantId, 0, 0, m_caster->GetGUID());
2530
2531 // add new enchanting if equipped
2532 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, true);
2533
2534 item_owner->RemoveTradeableItem(itemTarget);
2535 itemTarget->ClearSoulboundTradeable(item_owner);
2536 }
2537
2538 void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex)
2539 {
2540 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2541 return;
2542
2543 Player* player = m_caster->ToPlayer();
2544 if (!player)
2545 return;
2546
2547 if (!itemTarget)
2548 return;
2549
2550 uint32 enchant_id = effectInfo->MiscValue;
2551
2552 if (!enchant_id)
2553 {
2554 TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) has enchanting id 0.", m_spellInfo->Id, effIndex);
2555 return;
2556 }
2557
2558 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2559 if (!pEnchant)
2560 {
2561 TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) has a non-existing enchanting id %u ", m_spellInfo->Id, effIndex, enchant_id);
2562 return;
2563 }
2564
2565 // select enchantment duration
2566 uint32 duration;
2567
2568 // rogue family enchantments exception by duration
2569 if (m_spellInfo->Id == 38615)
2570 duration = 1800; // 30 mins
2571 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
2572 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
2573 duration = 3600; // 1 hour
2574 // shaman family enchantments
2575 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN)
2576 duration = 3600; // 30 mins
2577 // other cases with this SpellVisual already selected
2578 else if (m_spellInfo->GetSpellVisual() == 215)
2579 duration = 1800; // 30 mins
2580 // some fishing pole bonuses except Glow Worm which lasts full hour
2581 else if (m_spellInfo->GetSpellVisual() == 563 && m_spellInfo->Id != 64401)
2582 duration = 600; // 10 mins
2583 else if (m_spellInfo->Id == 29702)
2584 duration = 300; // 5 mins
2585 else if (m_spellInfo->Id == 37360)
2586 duration = 300; // 5 mins
2587 // default case
2588 else
2589 duration = 3600; // 1 hour
2590
2591 // item can be in trade slot and have owner diff. from caster
2592 Player* item_owner = itemTarget->GetOwner();
2593 if (!item_owner)
2594 return;
2595
2596 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2597 {
2598 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
2599 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2600 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2601 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2602 }
2603
2604 // remove old enchanting before applying new if equipped
2605 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, false);
2606
2607 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0, m_caster->GetGUID());
2608
2609 // add new enchanting if equipped
2610 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true);
2611 }
2612
2613 void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/)
2614 {
2615 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2616 return;
2617
2618 if (!m_caster->GetPetGUID().IsEmpty())
2619 return;
2620
2621 if (!unitTarget)
2622 return;
2623
2624 if (unitTarget->GetTypeId() != TYPEID_UNIT)
2625 return;
2626
2627 Creature* creatureTarget = unitTarget->ToCreature();
2628
2629 if (creatureTarget->IsPet())
2630 return;
2631
2632 if (m_caster->getClass() != CLASS_HUNTER)
2633 return;
2634
2635 // cast finish successfully
2636 //SendChannelUpdate(0);
2637 finish();
2638
2639 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget, m_spellInfo->Id);
2640 if (!pet) // in very specific state like near world end/etc.
2641 return;
2642
2643 // "kill" original creature
2644 creatureTarget->DespawnOrUnsummon();
2645
2646 uint8 level = (creatureTarget->GetLevelForTarget(m_caster) < (m_caster->GetLevelForTarget(creatureTarget) - 5)) ? (m_caster->GetLevelForTarget(creatureTarget) - 5) : creatureTarget->GetLevelForTarget(m_caster);
2647
2648 // prepare visual effect for levelup
2649 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
2650
2651 // add to world
2652 pet->GetMap()->AddToMap(pet->ToCreature());
2653
2654 // visual effect for levelup
2655 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
2656
2657 // caster have pet now
2658 m_caster->SetMinion(pet, true);
2659
2660 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2661 {
2662 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
2663 m_caster->ToPlayer()->PetSpellInitialize();
2664 }
2665 }
2666
2667 void Spell::EffectSummonPet(SpellEffIndex effIndex)
2668 {
2669 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2670 return;
2671
2672 Player* owner = NULL;
2673 if (m_originalCaster)
2674 {
2675 owner = m_originalCaster->ToPlayer();
2676 if (!owner && m_originalCaster->IsTotem())
2677 owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
2678 }
2679
2680 uint32 petentry = effectInfo->MiscValue;
2681
2682 if (!owner)
2683 {
2684 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(67);
2685 if (properties)
2686 SummonGuardian(effIndex, petentry, properties, 1);
2687 return;
2688 }
2689
2690 Pet* OldSummon = owner->GetPet();
2691
2692 // if pet requested type already exist
2693 if (OldSummon)
2694 {
2695 if (petentry == 0 || OldSummon->GetEntry() == petentry)
2696 {
2697 // pet in corpse state can't be summoned
2698 if (OldSummon->isDead())
2699 return;
2700
2701 ASSERT(OldSummon->GetMap() == owner->GetMap());
2702
2703 //OldSummon->GetMap()->Remove(OldSummon->ToCreature(), false);
2704
2705 float px, py, pz;
2706 owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
2707
2708 OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation());
2709 //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
2710 //OldSummon->SetMap(owner->GetMap());
2711 //owner->GetMap()->Add(OldSummon->ToCreature());
2712
2713 if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled())
2714 owner->ToPlayer()->PetSpellInitialize();
2715
2716 return;
2717 }
2718
2719 if (owner->GetTypeId() == TYPEID_PLAYER)
2720 owner->ToPlayer()->RemovePet(OldSummon, (OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT), false);
2721 else
2722 return;
2723 }
2724
2725 float x, y, z;
2726 owner->GetClosePoint(x, y, z, owner->GetObjectSize());
2727 Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
2728 if (!pet)
2729 return;
2730
2731 if (m_caster->GetTypeId() == TYPEID_UNIT)
2732 {
2733 if (m_caster->IsTotem())
2734 pet->SetReactState(REACT_AGGRESSIVE);
2735 else
2736 pet->SetReactState(REACT_DEFENSIVE);
2737 }
2738
2739 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
2740
2741 // generate new name for summon pet
2742 std::string new_name=sObjectMgr->GeneratePetName(petentry);
2743 if (!new_name.empty())
2744 pet->SetName(new_name);
2745
2746 ExecuteLogEffectSummonObject(effIndex, pet);
2747 }
2748
2749 void Spell::EffectLearnPetSpell(SpellEffIndex effIndex)
2750 {
2751 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2752 return;
2753
2754 if (!unitTarget)
2755 return;
2756
2757 if (unitTarget->ToPlayer())
2758 {
2759 EffectLearnSpell(effIndex);
2760 return;
2761 }
2762 Pet* pet = unitTarget->ToPet();
2763 if (!pet)
2764 return;
2765
2766 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell);
2767 if (!learn_spellproto)
2768 return;
2769
2770 pet->learnSpell(learn_spellproto->Id);
2771 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
2772 pet->GetOwner()->PetSpellInitialize();
2773 }
2774
2775 void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
2776 {
2777 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2778 return;
2779
2780 if (!unitTarget)
2781 return;
2782
2783 // this effect use before aura Taunt apply for prevent taunt already attacking target
2784 // for spell as marked "non effective at already attacking target"
2785 if (!unitTarget || !unitTarget->CanHaveThreatList()
2786 || unitTarget->GetVictim() == m_caster)
2787 {
2788 SendCastResult(SPELL_FAILED_DONT_REPORT);
2789 return;
2790 }
2791
2792 if (!unitTarget->getThreatManager().getOnlineContainer().empty())
2793 {
2794 // Also use this effect to set the taunter's threat to the taunted creature's highest value
2795 float myThreat = unitTarget->getThreatManager().getThreat(m_caster);
2796 float topThreat = unitTarget->getThreatManager().getOnlineContainer().getMostHated()->getThreat();
2797 if (topThreat > myThreat)
2798 unitTarget->getThreatManager().doAddThreat(m_caster, topThreat - myThreat);
2799
2800 //Set aggro victim to caster
2801 if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster))
2802 unitTarget->getThreatManager().setCurrentVictim(forcedVictim);
2803 }
2804
2805 if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE))
2806 unitTarget->ToCreature()->AI()->AttackStart(m_caster);
2807 }
2808
2809 void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
2810 {
2811 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
2812 return;
2813
2814 if (!unitTarget || !unitTarget->IsAlive())
2815 return;
2816
2817 // multiple weapon dmg effect workaround
2818 // execute only the last weapon damage
2819 // and handle all effects at once
2820 for (uint8 index = effIndex + 1; index < MAX_SPELL_EFFECTS; ++index)
2821 {
2822 SpellEffectInfo const* effect = GetEffect(index);
2823 if (!effect)
2824 continue;
2825 switch (effect->Effect)
2826 {
2827 case SPELL_EFFECT_WEAPON_DAMAGE:
2828 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2829 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2830 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2831 return; // we must calculate only at last weapon effect
2832 break;
2833 }
2834 }
2835
2836 // some spell specific modifiers
2837 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
2838 int32 fixed_bonus = 0;
2839 int32 spell_bonus = 0; // bonus specific for spell
2840
2841 switch (m_spellInfo->SpellFamilyName)
2842 {
2843 case SPELLFAMILY_WARRIOR:
2844 {
2845 // Devastate (player ones)
2846 if (m_spellInfo->SpellFamilyFlags[1] & 0x40)
2847 {
2848 // Player can apply only 58567 Sunder Armor effect.
2849 bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID());
2850 if (needCast)
2851 m_caster->CastSpell(unitTarget, 58567, true);
2852
2853 if (Aura* aur = unitTarget->GetAura(58567, m_caster->GetGUID()))
2854 {
2855 if (int32 num = (needCast ? 0 : 1))
2856 aur->ModStackAmount(num);
2857 fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget);
2858 }
2859 }
2860 break;
2861 }
2862 case SPELLFAMILY_ROGUE:
2863 {
2864 // Hemorrhage
2865 if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
2866 {
2867 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2868 m_caster->ToPlayer()->AddComboPoints(1, this);
2869 // 50% more damage with daggers
2870 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2871 if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true))
2872 if (item->GetTemplate()->GetSubClass() == ITEM_SUBCLASS_WEAPON_DAGGER)
2873 totalDamagePercentMod *= 1.5f;
2874 }
2875 break;
2876 }
2877 case SPELLFAMILY_SHAMAN:
2878 {
2879 // Skyshatter Harness item set bonus
2880 // Stormstrike
2881 if (AuraEffect* aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634))
2882 m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff);
2883 break;
2884 }
2885 case SPELLFAMILY_DRUID:
2886 {
2887 // Mangle (Cat): CP
2888 if (m_spellInfo->SpellFamilyFlags[1] & 0x400)
2889 {
2890 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2891 m_caster->ToPlayer()->AddComboPoints(1, this);
2892 }
2893 break;
2894 }
2895 case SPELLFAMILY_HUNTER:
2896 {
2897 // Kill Shot - bonus damage from Ranged Attack Power
2898 if (m_spellInfo->SpellFamilyFlags[1] & 0x800000)
2899 spell_bonus += int32(0.45f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK));
2900 break;
2901 }
2902 case SPELLFAMILY_DEATHKNIGHT:
2903 {
2904 // Blood Strike
2905 if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
2906 {
2907 if (SpellEffectInfo const* effect = GetEffect(EFFECT_2))
2908 {
2909 float bonusPct = effect->CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f;
2910 // Death Knight T8 Melee 4P Bonus
2911 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0))
2912 AddPct(bonusPct, aurEff->GetAmount());
2913 AddPct(totalDamagePercentMod, bonusPct);
2914 }
2915 break;
2916 }
2917 break;
2918 }
2919 }
2920
2921 bool normalized = false;
2922 float weaponDamagePercentMod = 1.0f;
2923 for (SpellEffectInfo const* effect : GetEffects())
2924 {
2925 if (!effect)
2926 continue;
2927 switch (effect->Effect)
2928 {
2929 case SPELL_EFFECT_WEAPON_DAMAGE:
2930 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2931 fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget);
2932 break;
2933 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2934 fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget);
2935 normalized = true;
2936 break;
2937 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2938 ApplyPct(weaponDamagePercentMod, CalculateDamage(effect->EffectIndex, unitTarget));
2939 break;
2940 default:
2941 break; // not weapon damage effect, just skip
2942 }
2943 }
2944
2945 // if (addPctMods) { percent mods are added in Unit::CalculateDamage } else { percent mods are added in Unit::MeleeDamageBonusDone }
2946 // this distinction is neccessary to properly inform the client about his autoattack damage values from Script_UnitDamage
2947 bool const addPctMods = !m_spellInfo->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && (m_spellSchoolMask & SPELL_SCHOOL_MASK_NORMAL);
2948 if (addPctMods)
2949 {
2950 UnitMods unitMod;
2951 switch (m_attackType)
2952 {
2953 default:
2954 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
2955 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
2956 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
2957 }
2958
2959 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
2960 if (fixed_bonus)
2961 fixed_bonus = int32(fixed_bonus * weapon_total_pct);
2962 if (spell_bonus)
2963 spell_bonus = int32(spell_bonus * weapon_total_pct);
2964 }
2965
2966 int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, addPctMods);
2967
2968 // Sequence is important
2969 for (SpellEffectInfo const* effect : GetEffects())
2970 {
2971 if (!effect)
2972 continue;
2973 // We assume that a spell have at most one fixed_bonus
2974 // and at most one weaponDamagePercentMod
2975 switch (effect->Effect)
2976 {
2977 case SPELL_EFFECT_WEAPON_DAMAGE:
2978 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2979 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2980 weaponDamage += fixed_bonus;
2981 break;
2982 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2983 weaponDamage = int32(weaponDamage * weaponDamagePercentMod);
2984 default:
2985 break; // not weapon damage effect, just skip
2986 }
2987 }
2988
2989 weaponDamage += spell_bonus;
2990 weaponDamage = int32(weaponDamage * totalDamagePercentMod);
2991
2992 // prevent negative damage
2993 uint32 eff_damage(std::max(weaponDamage, 0));
2994
2995 // Add melee damage bonuses (also check for negative)
2996 uint32 damageBonusDone = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo);
2997
2998 m_damage += unitTarget->MeleeDamageBonusTaken(m_caster, damageBonusDone, m_attackType, m_spellInfo);
2999 }
3000
3001 void Spell::EffectThreat(SpellEffIndex /*effIndex*/)
3002 {
3003 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3004 return;
3005
3006 if (!unitTarget || !unitTarget->IsAlive() || !m_caster->IsAlive())
3007 return;
3008
3009 if (!unitTarget->CanHaveThreatList())
3010 return;
3011
3012 unitTarget->AddThreat(m_caster, float(damage));
3013 }
3014
3015 void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
3016 {
3017 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3018 return;
3019
3020 if (!unitTarget || !unitTarget->IsAlive())
3021 return;
3022
3023 int32 addhealth = 0;
3024
3025 // damage == 0 - heal for caster max health
3026 if (damage == 0)
3027 addhealth = m_caster->GetMaxHealth();
3028 else
3029 addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
3030
3031 m_healing += addhealth;
3032 }
3033
3034 void Spell::EffectInterruptCast(SpellEffIndex effIndex)
3035 {
3036 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
3037 return;
3038
3039 if (!unitTarget || !unitTarget->IsAlive())
3040 return;
3041
3042 /// @todo not all spells that used this effect apply cooldown at school spells
3043 // also exist case: apply cooldown to interrupted cast only and to all spells
3044 // there is no CURRENT_AUTOREPEAT_SPELL spells that can be interrupted
3045 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_AUTOREPEAT_SPELL; ++i)
3046 {
3047 if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i)))
3048 {
3049 SpellInfo const* curSpellInfo = spell->m_spellInfo;
3050 // check if we can interrupt spell
3051 if ((spell->getState() == SPELL_STATE_CASTING
3052 || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f))
3053 && (curSpellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
3054 && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT)
3055 || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->HasChannelInterruptFlag(CHANNEL_INTERRUPT_FLAG_INTERRUPT))))
3056 {
3057 if (m_originalCaster)
3058 {
3059 int32 duration = m_spellInfo->GetDuration();
3060 unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
3061 m_originalCaster->ProcSkillsAndAuras(unitTarget, PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG, PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_HIT, PROC_HIT_INTERRUPT, nullptr, nullptr, nullptr);
3062 }
3063 ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
3064 unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
3065 }
3066 }
3067 }
3068 }
3069
3070 void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
3071 {
3072 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
3073 return;
3074
3075 WorldObject* target = focusObject;
3076 if (!target)
3077 target = m_caster;
3078
3079 float x, y, z;
3080 if (m_targets.HasDst())
3081 destTarget->GetPosition(x, y, z);
3082 else
3083 m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
3084
3085 Map* map = target->GetMap();
3086 Position pos = Position(x, y, z, target->GetOrientation());
3087 QuaternionData rot = QuaternionData::fromEulerAnglesZYX(target->GetOrientation(), 0.f, 0.f);
3088 GameObject* go = GameObject::CreateGameObject(effectInfo->MiscValue, map, pos, rot, 255, GO_STATE_READY);
3089 if (!go)
3090 return;
3091
3092 PhasingHandler::InheritPhaseShift(go, m_caster);
3093
3094 int32 duration = m_spellInfo->CalcDuration(m_caster);
3095
3096 go->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
3097 go->SetSpellId(m_spellInfo->Id);
3098
3099 ExecuteLogEffectSummonObject(effIndex, go);
3100
3101 // Wild object not have owner and check clickable by players
3102 map->AddToMap(go);
3103
3104 if (go->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP)
3105 if (Player* player = m_caster->ToPlayer())
3106 if (Battleground* bg = player->GetBattleground())
3107 bg->SetDroppedFlagGUID(go->GetGUID(), player->GetTeam() == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE);
3108
3109 if (GameObject* linkedTrap = go->GetLinkedTrap())
3110 {
3111 PhasingHandler::InheritPhaseShift(linkedTrap , m_caster);
3112
3113 linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
3114 linkedTrap->SetSpellId(m_spellInfo->Id);
3115
3116 ExecuteLogEffectSummonObject(effIndex, linkedTrap);
3117 }
3118 }
3119
3120 void Spell::EffectScriptEffect(SpellEffIndex effIndex)
3121 {
3122 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3123 return;
3124
3125 /// @todo we must implement hunter pet summon at login there (spell 6962)
3126
3127 switch (m_spellInfo->SpellFamilyName)
3128 {
3129 case SPELLFAMILY_GENERIC:
3130 {
3131 switch (m_spellInfo->Id)
3132 {
3133 case 55693: // Remove Collapsing Cave Aura
3134 if (!unitTarget)
3135 return;
3136 unitTarget->RemoveAurasDueToSpell(effectInfo->CalcValue());
3137 break;
3138 // Bending Shinbone
3139 case 8856:
3140 {
3141 if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
3142 return;
3143
3144 uint32 spell_id = roll_chance_i(20) ? 8854 : 8855;
3145
3146 m_caster->CastSpell(m_caster, spell_id, true, NULL);
3147 return;
3148 }
3149 // Brittle Armor - need remove one 24575 Brittle Armor aura
3150 case 24590:
3151 unitTarget->RemoveAuraFromStack(24575);
3152 return;
3153 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
3154 case 26465:
3155 unitTarget->RemoveAuraFromStack(26464);
3156 return;
3157 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
3158 case 22539:
3159 case 22972:
3160 case 22975:
3161 case 22976:
3162 case 22977:
3163 case 22978:
3164 case 22979:
3165 case 22980:
3166 case 22981:
3167 case 22982:
3168 case 22983:
3169 case 22984:
3170 case 22985:
3171 {
3172 if (!unitTarget || !unitTarget->IsAlive())
3173 return;
3174
3175 // Onyxia Scale Cloak
3176 if (unitTarget->HasAura(22683))
3177 return;
3178
3179 // Shadow Flame
3180 m_caster->CastSpell(unitTarget, 22682, true);
3181 return;
3182 }
3183 // Mirren's Drinking Hat
3184 case 29830:
3185 {
3186 uint32 item = 0;
3187 switch (urand(1, 6))
3188 {
3189 case 1:
3190 case 2:
3191 case 3:
3192 item = 23584; break; // Loch Modan Lager
3193 case 4:
3194 case 5:
3195 item = 23585; break; // Stouthammer Lite
3196 case 6:
3197 item = 23586; break; // Aerie Peak Pale Ale
3198 }
3199 if (item)
3200 DoCreateItem(effIndex, item);
3201 break;
3202 }
3203 case 20589: // Escape artist
3204 case 30918: // Improved Sprint
3205 {
3206 // Removes snares and roots.
3207 unitTarget->RemoveMovementImpairingAuras();
3208 break;
3209 }
3210 // Plant Warmaul Ogre Banner
3211 case 32307:
3212 if (Player* caster = m_caster->ToPlayer())
3213 {
3214 caster->RewardPlayerAndGroupAtEvent(18388, unitTarget);
3215 if (Creature* target = unitTarget->ToCreature())
3216 {
3217 target->setDeathState(CORPSE);
3218 target->RemoveCorpse();
3219 }
3220 }
3221 break;
3222 // Mug Transformation
3223 case 41931:
3224 {
3225 if (m_caster->GetTypeId() != TYPEID_PLAYER)
3226 return;
3227
3228 uint8 bag = 19;
3229 uint8 slot = 0;
3230 Item* item = NULL;
3231
3232 while (bag) // 256 = 0 due to var type
3233 {
3234 item = m_caster->ToPlayer()->GetItemByPos(bag, slot);
3235 if (item && item->GetEntry() == 38587)
3236 break;
3237
3238 ++slot;
3239 if (slot == 39)
3240 {
3241 slot = 0;
3242 ++bag;
3243 }
3244 }
3245 if (bag)
3246 {
3247 if (m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag, slot, true);
3248 else m_caster->ToPlayer()->GetItemByPos(bag, slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount()-1);
3249 // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
3250 m_caster->CastSpell(m_caster, 42518, true);
3251 return;
3252 }
3253 break;
3254 }
3255 // Brutallus - Burn
3256 case 45141:
3257 case 45151:
3258 {
3259 //Workaround for Range ... should be global for every ScriptEffect
3260 float radius = effectInfo->CalcRadius();
3261 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster)
3262 unitTarget->CastSpell(unitTarget, 46394, true);
3263
3264 break;
3265 }
3266 // Goblin Weather Machine
3267 case 46203:
3268 {
3269 if (!unitTarget)
3270 return;
3271
3272 uint32 spellId = 0;
3273 switch (rand32() % 4)
3274 {
3275 case 0: spellId = 46740; break;
3276 case 1: spellId = 46739; break;
3277 case 2: spellId = 46738; break;
3278 case 3: spellId = 46736; break;
3279 }
3280 unitTarget->CastSpell(unitTarget, spellId, true);
3281 break;
3282 }
3283 // 5, 000 Gold
3284 case 46642:
3285 {
3286 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3287 return;
3288
3289 unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD);
3290
3291 break;
3292 }
3293 // Death Knight Initiate Visual
3294 case 51519:
3295 {
3296 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
3297 return;
3298
3299 uint32 iTmpSpellId = 0;
3300 switch (unitTarget->GetDisplayId())
3301 {
3302 case 25369: iTmpSpellId = 51552; break; // bloodelf female
3303 case 25373: iTmpSpellId = 51551; break; // bloodelf male
3304 case 25363: iTmpSpellId = 51542; break; // draenei female
3305 case 25357: iTmpSpellId = 51541; break; // draenei male
3306 case 25361: iTmpSpellId = 51537; break; // dwarf female
3307 case 25356: iTmpSpellId = 51538; break; // dwarf male
3308 case 25372: iTmpSpellId = 51550; break; // forsaken female
3309 case 25367: iTmpSpellId = 51549; break; // forsaken male
3310 case 25362: iTmpSpellId = 51540; break; // gnome female
3311 case 25359: iTmpSpellId = 51539; break; // gnome male
3312 case 25355: iTmpSpellId = 51534; break; // human female
3313 case 25354: iTmpSpellId = 51520; break; // human male
3314 case 25360: iTmpSpellId = 51536; break; // nightelf female
3315 case 25358: iTmpSpellId = 51535; break; // nightelf male
3316 case 25368: iTmpSpellId = 51544; break; // orc female
3317 case 25364: iTmpSpellId = 51543; break; // orc male
3318 case 25371: iTmpSpellId = 51548; break; // tauren female
3319 case 25366: iTmpSpellId = 51547; break; // tauren male
3320 case 25370: iTmpSpellId = 51545; break; // troll female
3321 case 25365: iTmpSpellId = 51546; break; // troll male
3322 default: return;
3323 }
3324
3325 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
3326 Creature* npc = unitTarget->ToCreature();
3327 npc->LoadEquipment();
3328 return;
3329 }
3330 // Deathbolt from Thalgran Blightbringer
3331 // reflected by Freya's Ward
3332 // Retribution by Sevenfold Retribution
3333 case 51854:
3334 {
3335 if (!unitTarget)
3336 return;
3337 if (unitTarget->HasAura(51845))
3338 unitTarget->CastSpell(m_caster, 51856, true);
3339 else
3340 m_caster->CastSpell(unitTarget, 51855, true);
3341 break;
3342 }
3343 // Summon Ghouls On Scarlet Crusade
3344 case 51904:
3345 {
3346 if (!m_targets.HasDst())
3347 return;
3348
3349 float x, y, z;
3350 float radius = effectInfo->CalcRadius();
3351 for (uint8 i = 0; i < 15; ++i)
3352 {
3353 m_caster->GetRandomPoint(*destTarget, radius, x, y, z);
3354 m_caster->CastSpell(x, y, z, 54522, true);
3355 }
3356 break;
3357 }
3358 case 52173: // Coyote Spirit Despawn
3359 case 60243: // Blood Parrot Despawn
3360 if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsSummon())
3361 unitTarget->ToTempSummon()->UnSummon();
3362 return;
3363 case 52479: // Gift of the Harvester
3364 if (unitTarget && m_originalCaster)
3365 m_originalCaster->CastSpell(unitTarget, urand(0, 1) ? damage : 52505, true);
3366 return;
3367 case 53110: // Devour Humanoid
3368 if (unitTarget)
3369