a03b124f4b4b6aff1df7d769d5f6bf6b5a80ee5e
[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 int32 duration = m_spellInfo->CalcDuration(m_originalCaster);
1978
1979 TempSummon* summon = NULL;
1980
1981 // determine how many units should be summoned
1982 uint32 numSummons;
1983
1984 // some spells need to summon many units, for those spells number of summons is stored in effect value
1985 // however so far noone found a generic check to find all of those (there's no related data in summonproperties.dbc
1986 // and in spell attributes, possibly we need to add a table for those)
1987 // so here's a list of MiscValueB values, which is currently most generic check
1988 switch (effectInfo->MiscValueB)
1989 {
1990 case 64:
1991 case 61:
1992 case 1101:
1993 case 66:
1994 case 648:
1995 case 2301:
1996 case 1061:
1997 case 1261:
1998 case 629:
1999 case 181:
2000 case 715:
2001 case 1562:
2002 case 833:
2003 case 1161:
2004 case 713:
2005 numSummons = (damage > 0) ? damage : 1;
2006 break;
2007 default:
2008 numSummons = 1;
2009 break;
2010 }
2011
2012 switch (properties->Control)
2013 {
2014 case SUMMON_CATEGORY_WILD:
2015 case SUMMON_CATEGORY_ALLY:
2016 case SUMMON_CATEGORY_UNK:
2017 if (properties->Flags & 512)
2018 {
2019 SummonGuardian(effIndex, entry, properties, numSummons);
2020 break;
2021 }
2022 switch (properties->Title)
2023 {
2024 case SUMMON_TYPE_PET:
2025 case SUMMON_TYPE_GUARDIAN:
2026 case SUMMON_TYPE_GUARDIAN2:
2027 case SUMMON_TYPE_MINION:
2028 SummonGuardian(effIndex, entry, properties, numSummons);
2029 break;
2030 // Summons a vehicle, but doesn't force anyone to enter it (see SUMMON_CATEGORY_VEHICLE)
2031 case SUMMON_TYPE_VEHICLE:
2032 case SUMMON_TYPE_VEHICLE2:
2033 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2034 break;
2035 case SUMMON_TYPE_LIGHTWELL:
2036 case SUMMON_TYPE_TOTEM:
2037 {
2038 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2039 if (!summon || !summon->IsTotem())
2040 return;
2041
2042 if (damage) // if not spell info, DB values used
2043 {
2044 summon->SetMaxHealth(damage);
2045 summon->SetHealth(damage);
2046 }
2047 break;
2048 }
2049 case SUMMON_TYPE_MINIPET:
2050 {
2051 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2052 if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION))
2053 return;
2054
2055 summon->SelectLevel(); // some summoned creaters have different from 1 DB data for level/hp
2056 summon->SetUInt64Value(UNIT_NPC_FLAGS, summon->GetCreatureTemplate()->npcflag);
2057
2058 summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
2059
2060 summon->AI()->EnterEvadeMode();
2061 break;
2062 }
2063 default:
2064 {
2065 float radius = effectInfo->CalcRadius();
2066
2067 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2068
2069 for (uint32 count = 0; count < numSummons; ++count)
2070 {
2071 Position pos;
2072 if (count == 0)
2073 pos = *destTarget;
2074 else
2075 // randomize position for multiple summons
2076 pos = m_caster->GetRandomPoint(*destTarget, radius);
2077
2078 summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration);
2079 if (!summon)
2080 continue;
2081
2082 if (properties->Control == SUMMON_CATEGORY_ALLY)
2083 {
2084 summon->SetOwnerGUID(m_originalCaster->GetGUID());
2085 summon->setFaction(m_originalCaster->getFaction());
2086 summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
2087 }
2088
2089 ExecuteLogEffectSummonObject(effIndex, summon);
2090 }
2091 return;
2092 }
2093 }//switch
2094 break;
2095 case SUMMON_CATEGORY_PET:
2096 SummonGuardian(effIndex, entry, properties, numSummons);
2097 break;
2098 case SUMMON_CATEGORY_PUPPET:
2099 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2100 break;
2101 case SUMMON_CATEGORY_VEHICLE:
2102 // Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker
2103 // to cast a ride vehicle spell on the summoned unit.
2104 summon = m_originalCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_caster, m_spellInfo->Id);
2105 if (!summon || !summon->IsVehicle())
2106 return;
2107
2108 // The spell that this effect will trigger. It has SPELL_AURA_CONTROL_VEHICLE
2109 uint32 spellId = VEHICLE_SPELL_RIDE_HARDCODED;
2110 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectInfo->CalcValue());
2111 if (spellInfo && spellInfo->HasAura(m_originalCaster->GetMap()->GetDifficultyID(), SPELL_AURA_CONTROL_VEHICLE))
2112 spellId = spellInfo->Id;
2113
2114 // Hard coded enter vehicle spell
2115 m_originalCaster->CastSpell(summon, spellId, true);
2116
2117 uint32 faction = properties->Faction;
2118 if (!faction)
2119 faction = m_originalCaster->getFaction();
2120
2121 summon->setFaction(faction);
2122 break;
2123 }
2124
2125 if (summon)
2126 {
2127 summon->SetCreatorGUID(m_originalCaster->GetGUID());
2128 ExecuteLogEffectSummonObject(effIndex, summon);
2129 }
2130 }
2131
2132 void Spell::EffectLearnSpell(SpellEffIndex effIndex)
2133 {
2134 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2135 return;
2136
2137 if (!unitTarget)
2138 return;
2139
2140 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2141 {
2142 if (unitTarget->ToPet())
2143 EffectLearnPetSpell(effIndex);
2144 return;
2145 }
2146
2147 Player* player = unitTarget->ToPlayer();
2148
2149 uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : effectInfo->TriggerSpell;
2150 player->LearnSpell(spellToLearn, false);
2151
2152 TC_LOG_DEBUG("spells", "Spell: %s has learned spell %u from %s", player->GetGUID().ToString().c_str(), spellToLearn, m_caster->GetGUID().ToString().c_str());
2153 }
2154
2155 void Spell::EffectDispel(SpellEffIndex effIndex)
2156 {
2157 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2158 return;
2159
2160 if (!unitTarget)
2161 return;
2162
2163 // Create dispel mask by dispel type
2164 uint32 dispel_type = effectInfo->MiscValue;
2165 uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(dispel_type));
2166
2167 DispelChargesList dispel_list;
2168 unitTarget->GetDispellableAuraList(m_caster, dispelMask, dispel_list);
2169 if (dispel_list.empty())
2170 return;
2171
2172 // Ok if exist some buffs for dispel try dispel it
2173 DispelChargesList success_list;
2174 WorldPackets::Spells::DispelFailed dispelFailed;
2175 dispelFailed.CasterGUID = m_caster->GetGUID();
2176 dispelFailed.VictimGUID = unitTarget->GetGUID();
2177 dispelFailed.SpellID = m_spellInfo->Id;
2178
2179 // dispel N = damage buffs (or while exist buffs for dispel)
2180 for (int32 count = 0; count < damage && !dispel_list.empty();)
2181 {
2182 // Random select buff for dispel
2183 DispelChargesList::iterator itr = dispel_list.begin();
2184 std::advance(itr, urand(0, dispel_list.size() - 1));
2185
2186 int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
2187 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
2188 if (!chance)
2189 {
2190 dispel_list.erase(itr);
2191 continue;
2192 }
2193 else
2194 {
2195 if (roll_chance_i(chance))
2196 {
2197 bool alreadyListed = false;
2198 for (DispelChargesList::iterator successItr = success_list.begin(); successItr != success_list.end(); ++successItr)
2199 {
2200 if (successItr->first->GetId() == itr->first->GetId())
2201 {
2202 ++successItr->second;
2203 alreadyListed = true;
2204 }
2205 }
2206 if (!alreadyListed)
2207 success_list.push_back(std::make_pair(itr->first, 1));
2208 --itr->second;
2209 if (itr->second <= 0)
2210 dispel_list.erase(itr);
2211 }
2212 else
2213 dispelFailed.FailedSpells.push_back(int32(itr->first->GetId()));
2214
2215 ++count;
2216 }
2217 }
2218
2219 if (!dispelFailed.FailedSpells.empty())
2220 m_caster->SendMessageToSet(dispelFailed.Write(), true);
2221
2222 if (success_list.empty())
2223 return;
2224
2225 WorldPackets::CombatLog::SpellDispellLog spellDispellLog;
2226 spellDispellLog.IsBreak = false; // TODO: use me
2227 spellDispellLog.IsSteal = false;
2228
2229 spellDispellLog.TargetGUID = unitTarget->GetGUID();
2230 spellDispellLog.CasterGUID = m_caster->GetGUID();
2231 spellDispellLog.DispelledBySpellID = m_spellInfo->Id;
2232
2233 for (std::pair<Aura*, uint8> const& dispellCharge : success_list)
2234 {
2235 WorldPackets::CombatLog::SpellDispellData dispellData;
2236 dispellData.SpellID = dispellCharge.first->GetId();
2237 dispellData.Harmful = false; // TODO: use me
2238 dispellData.Rolled = boost::none; // TODO: use me
2239 dispellData.Needed = boost::none; // TODO: use me
2240
2241 unitTarget->RemoveAurasDueToSpellByDispel(dispellCharge.first->GetId(), m_spellInfo->Id, dispellCharge.first->GetCasterGUID(), m_caster, dispellCharge.second);
2242
2243 spellDispellLog.DispellData.emplace_back(dispellData);
2244 }
2245
2246 m_caster->SendMessageToSet(spellDispellLog.Write(), true);
2247
2248 CallScriptSuccessfulDispel(effIndex);
2249 }
2250
2251 void Spell::EffectDualWield(SpellEffIndex /*effIndex*/)
2252 {
2253 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2254 return;
2255
2256 unitTarget->SetCanDualWield(true);
2257 }
2258
2259 void Spell::EffectPull(SpellEffIndex effIndex)
2260 {
2261 /// @todo create a proper pull towards distract spell center for distract
2262 EffectNULL(effIndex);
2263 }
2264
2265 void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
2266 {
2267 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2268 return;
2269
2270 // Check for possible target
2271 if (!unitTarget || unitTarget->IsInCombat())
2272 return;
2273
2274 // target must be OK to do this
2275 if (unitTarget->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING))
2276 return;
2277
2278 unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
2279 unitTarget->ClearUnitState(UNIT_STATE_MOVING);
2280
2281 if (unitTarget->GetTypeId() == TYPEID_UNIT)
2282 unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
2283 }
2284
2285 void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
2286 {
2287 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2288 return;
2289
2290 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2291 return;
2292
2293 // victim must be creature and attackable
2294 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget))
2295 return;
2296
2297 // victim have to be alive and humanoid or undead
2298 if (unitTarget->IsAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
2299 m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(), LOOT_PICKPOCKETING);
2300 }
2301
2302 void Spell::EffectAddFarsight(SpellEffIndex /*effIndex*/)
2303 {
2304 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2305 return;
2306
2307 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2308 return;
2309
2310 float radius = effectInfo->CalcRadius();
2311 int32 duration = m_spellInfo->CalcDuration(m_caster);
2312 // Caster not in world, might be spell triggered from aura removal
2313 if (!m_caster->IsInWorld())
2314 return;
2315
2316 DynamicObject* dynObj = new DynamicObject(true);
2317 if (!dynObj->CreateDynamicObject(m_caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), m_caster, m_spellInfo, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS, m_SpellVisual))
2318 {
2319 delete dynObj;
2320 return;
2321 }
2322
2323 dynObj->SetDuration(duration);
2324 dynObj->SetCasterViewpoint();
2325 }
2326
2327 void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)
2328 {
2329 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2330 return;
2331
2332 if (!unitTarget || m_caster->GetTypeId() == TYPEID_PLAYER)
2333 return;
2334
2335 unitTarget->ToPlayer()->SendRespecWipeConfirm(m_caster->GetGUID(), sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : unitTarget->ToPlayer()->GetNextResetTalentsCost());
2336 }
2337
2338 void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex /*effIndex*/)
2339 {
2340 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2341 return;
2342
2343 if (!unitTarget)
2344 return;
2345
2346 if (unitTarget->IsInFlight())
2347 return;
2348
2349 float dis = effectInfo->CalcRadius(m_caster);
2350
2351 float fx, fy, fz;
2352 m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis);
2353
2354 unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
2355 }
2356
2357 void Spell::EffectLearnSkill(SpellEffIndex /*effIndex*/)
2358 {
2359 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2360 return;
2361
2362 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2363 return;
2364
2365 if (damage < 0)
2366 return;
2367
2368 uint32 skillid = effectInfo->MiscValue;
2369 SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass());
2370 if (!rcEntry)
2371 return;
2372
2373 SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcEntry->SkillTierID);
2374 if (!tier)
2375 return;
2376
2377 uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid);
2378 unitTarget->ToPlayer()->SetSkill(skillid, effectInfo->CalcValue(), std::max<uint16>(skillval, 1), tier->Value[damage - 1]);
2379 }
2380
2381 void Spell::EffectPlayMovie(SpellEffIndex /*effIndex*/)
2382 {
2383 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2384 return;
2385
2386 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2387 return;
2388
2389 uint32 movieId = effectInfo->MiscValue;
2390 if (!sMovieStore.LookupEntry(movieId))
2391 return;
2392
2393 unitTarget->ToPlayer()->SendMovieStart(movieId);
2394 }
2395
2396 void Spell::EffectTradeSkill(SpellEffIndex /*effIndex*/)
2397 {
2398 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2399 return;
2400
2401 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2402 return;
2403 // uint32 skillid = m_spellInfo->Effects[i].MiscValue;
2404 // uint16 skillmax = unitTarget->ToPlayer()->(skillid);
2405 // m_caster->ToPlayer()->SetSkill(skillid, skillval?skillval:1, skillmax+75);
2406 }
2407
2408 void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
2409 {
2410 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2411 return;
2412
2413 if (!itemTarget)
2414 return;
2415
2416 Player* player = m_caster->ToPlayer();
2417 if (!player)
2418 return;
2419
2420 // Handle vellums
2421 if (itemTarget->IsVellum())
2422 {
2423 // destroy one vellum from stack
2424 uint32 count = 1;
2425 player->DestroyItemCount(itemTarget, count, true);
2426 unitTarget = player;
2427 // and add a scroll
2428 DoCreateItem(effIndex, effectInfo->ItemType);
2429 itemTarget = NULL;
2430 m_targets.SetItemTarget(NULL);
2431 }
2432 else
2433 {
2434 // do not increase skill if vellum used
2435 if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST))
2436 player->UpdateCraftSkill(m_spellInfo->Id);
2437
2438 uint32 enchant_id = effectInfo->MiscValue;
2439 if (!enchant_id)
2440 return;
2441
2442 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2443 if (!pEnchant)
2444 return;
2445
2446 // item can be in trade slot and have owner diff. from caster
2447 Player* item_owner = itemTarget->GetOwner();
2448 if (!item_owner)
2449 return;
2450
2451 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2452 {
2453 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2454 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2455 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2456 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2457 }
2458
2459 // remove old enchanting before applying new if equipped
2460 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, false);
2461
2462 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0, m_caster->GetGUID());
2463
2464 // add new enchanting if equipped
2465 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, true);
2466
2467 item_owner->RemoveTradeableItem(itemTarget);
2468 itemTarget->ClearSoulboundTradeable(item_owner);
2469 }
2470 }
2471
2472 void Spell::EffectEnchantItemPrismatic(SpellEffIndex /*effIndex*/)
2473 {
2474 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2475 return;
2476
2477 if (!itemTarget)
2478 return;
2479
2480 Player* player = m_caster->ToPlayer();
2481 if (!player)
2482 return;
2483
2484 uint32 enchantId = effectInfo->MiscValue;
2485 if (!enchantId)
2486 return;
2487
2488 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2489 if (!enchant)
2490 return;
2491
2492 // support only enchantings with add socket in this slot
2493 {
2494 bool add_socket = false;
2495 for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
2496 {
2497 if (enchant->Effect[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
2498 {
2499 add_socket = true;
2500 break;
2501 }
2502 }
2503 if (!add_socket)
2504 {
2505 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.",
2506 m_spellInfo->Id, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC, ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
2507 return;
2508 }
2509 }
2510
2511 // item can be in trade slot and have owner diff. from caster
2512 Player* item_owner = itemTarget->GetOwner();
2513 if (!item_owner)
2514 return;
2515
2516 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2517 {
2518 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2519 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2520 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2521 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2522 }
2523
2524 // remove old enchanting before applying new if equipped
2525 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, false);
2526
2527 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchantId, 0, 0, m_caster->GetGUID());
2528
2529 // add new enchanting if equipped
2530 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, true);
2531
2532 item_owner->RemoveTradeableItem(itemTarget);
2533 itemTarget->ClearSoulboundTradeable(item_owner);
2534 }
2535
2536 void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex)
2537 {
2538 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2539 return;
2540
2541 Player* player = m_caster->ToPlayer();
2542 if (!player)
2543 return;
2544
2545 if (!itemTarget)
2546 return;
2547
2548 uint32 enchant_id = effectInfo->MiscValue;
2549
2550 if (!enchant_id)
2551 {
2552 TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) has enchanting id 0.", m_spellInfo->Id, effIndex);
2553 return;
2554 }
2555
2556 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2557 if (!pEnchant)
2558 {
2559 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);
2560 return;
2561 }
2562
2563 // select enchantment duration
2564 uint32 duration;
2565
2566 // rogue family enchantments exception by duration
2567 if (m_spellInfo->Id == 38615)
2568 duration = 1800; // 30 mins
2569 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
2570 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
2571 duration = 3600; // 1 hour
2572 // shaman family enchantments
2573 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN)
2574 duration = 3600; // 30 mins
2575 // other cases with this SpellVisual already selected
2576 else if (m_spellInfo->GetSpellVisual() == 215)
2577 duration = 1800; // 30 mins
2578 // some fishing pole bonuses except Glow Worm which lasts full hour
2579 else if (m_spellInfo->GetSpellVisual() == 563 && m_spellInfo->Id != 64401)
2580 duration = 600; // 10 mins
2581 else if (m_spellInfo->Id == 29702)
2582 duration = 300; // 5 mins
2583 else if (m_spellInfo->Id == 37360)
2584 duration = 300; // 5 mins
2585 // default case
2586 else
2587 duration = 3600; // 1 hour
2588
2589 // item can be in trade slot and have owner diff. from caster
2590 Player* item_owner = itemTarget->GetOwner();
2591 if (!item_owner)
2592 return;
2593
2594 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2595 {
2596 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
2597 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2598 itemTarget->GetTemplate()->GetDefaultLocaleName(), itemTarget->GetEntry(),
2599 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2600 }
2601
2602 // remove old enchanting before applying new if equipped
2603 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, false);
2604
2605 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0, m_caster->GetGUID());
2606
2607 // add new enchanting if equipped
2608 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true);
2609 }
2610
2611 void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/)
2612 {
2613 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2614 return;
2615
2616 if (!m_caster->GetPetGUID().IsEmpty())
2617 return;
2618
2619 if (!unitTarget)
2620 return;
2621
2622 if (unitTarget->GetTypeId() != TYPEID_UNIT)
2623 return;
2624
2625 Creature* creatureTarget = unitTarget->ToCreature();
2626
2627 if (creatureTarget->IsPet())
2628 return;
2629
2630 if (m_caster->getClass() != CLASS_HUNTER)
2631 return;
2632
2633 // cast finish successfully
2634 //SendChannelUpdate(0);
2635 finish();
2636
2637 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget, m_spellInfo->Id);
2638 if (!pet) // in very specific state like near world end/etc.
2639 return;
2640
2641 // "kill" original creature
2642 creatureTarget->DespawnOrUnsummon();
2643
2644 uint8 level = (creatureTarget->GetLevelForTarget(m_caster) < (m_caster->GetLevelForTarget(creatureTarget) - 5)) ? (m_caster->GetLevelForTarget(creatureTarget) - 5) : creatureTarget->GetLevelForTarget(m_caster);
2645
2646 // prepare visual effect for levelup
2647 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
2648
2649 // add to world
2650 pet->GetMap()->AddToMap(pet->ToCreature());
2651
2652 // visual effect for levelup
2653 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
2654
2655 // caster have pet now
2656 m_caster->SetMinion(pet, true);
2657
2658 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2659 {
2660 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
2661 m_caster->ToPlayer()->PetSpellInitialize();
2662 }
2663 }
2664
2665 void Spell::EffectSummonPet(SpellEffIndex effIndex)
2666 {
2667 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2668 return;
2669
2670 Player* owner = NULL;
2671 if (m_originalCaster)
2672 {
2673 owner = m_originalCaster->ToPlayer();
2674 if (!owner && m_originalCaster->IsTotem())
2675 owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
2676 }
2677
2678 uint32 petentry = effectInfo->MiscValue;
2679
2680 if (!owner)
2681 {
2682 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(67);
2683 if (properties)
2684 SummonGuardian(effIndex, petentry, properties, 1);
2685 return;
2686 }
2687
2688 Pet* OldSummon = owner->GetPet();
2689
2690 // if pet requested type already exist
2691 if (OldSummon)
2692 {
2693 if (petentry == 0 || OldSummon->GetEntry() == petentry)
2694 {
2695 // pet in corpse state can't be summoned
2696 if (OldSummon->isDead())
2697 return;
2698
2699 ASSERT(OldSummon->GetMap() == owner->GetMap());
2700
2701 //OldSummon->GetMap()->Remove(OldSummon->ToCreature(), false);
2702
2703 float px, py, pz;
2704 owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
2705
2706 OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation());
2707 //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
2708 //OldSummon->SetMap(owner->GetMap());
2709 //owner->GetMap()->Add(OldSummon->ToCreature());
2710
2711 if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled())
2712 owner->ToPlayer()->PetSpellInitialize();
2713
2714 return;
2715 }
2716
2717 if (owner->GetTypeId() == TYPEID_PLAYER)
2718 owner->ToPlayer()->RemovePet(OldSummon, (OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT), false);
2719 else
2720 return;
2721 }
2722
2723 float x, y, z;
2724 owner->GetClosePoint(x, y, z, owner->GetObjectSize());
2725 Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
2726 if (!pet)
2727 return;
2728
2729 if (m_caster->GetTypeId() == TYPEID_UNIT)
2730 {
2731 if (m_caster->IsTotem())
2732 pet->SetReactState(REACT_AGGRESSIVE);
2733 else
2734 pet->SetReactState(REACT_DEFENSIVE);
2735 }
2736
2737 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
2738
2739 // generate new name for summon pet
2740 std::string new_name=sObjectMgr->GeneratePetName(petentry);
2741 if (!new_name.empty())
2742 pet->SetName(new_name);
2743
2744 ExecuteLogEffectSummonObject(effIndex, pet);
2745 }
2746
2747 void Spell::EffectLearnPetSpell(SpellEffIndex effIndex)
2748 {
2749 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2750 return;
2751
2752 if (!unitTarget)
2753 return;
2754
2755 if (unitTarget->ToPlayer())
2756 {
2757 EffectLearnSpell(effIndex);
2758 return;
2759 }
2760 Pet* pet = unitTarget->ToPet();
2761 if (!pet)
2762 return;
2763
2764 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(effectInfo->TriggerSpell);
2765 if (!learn_spellproto)
2766 return;
2767
2768 pet->learnSpell(learn_spellproto->Id);
2769 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
2770 pet->GetOwner()->PetSpellInitialize();
2771 }
2772
2773 void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
2774 {
2775 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2776 return;
2777
2778 if (!unitTarget)
2779 return;
2780
2781 // this effect use before aura Taunt apply for prevent taunt already attacking target
2782 // for spell as marked "non effective at already attacking target"
2783 if (!unitTarget || !unitTarget->CanHaveThreatList()
2784 || unitTarget->GetVictim() == m_caster)
2785 {
2786 SendCastResult(SPELL_FAILED_DONT_REPORT);
2787 return;
2788 }
2789
2790 if (!unitTarget->getThreatManager().getOnlineContainer().empty())
2791 {
2792 // Also use this effect to set the taunter's threat to the taunted creature's highest value
2793 float myThreat = unitTarget->getThreatManager().getThreat(m_caster);
2794 float topThreat = unitTarget->getThreatManager().getOnlineContainer().getMostHated()->getThreat();
2795 if (topThreat > myThreat)
2796 unitTarget->getThreatManager().doAddThreat(m_caster, topThreat - myThreat);
2797
2798 //Set aggro victim to caster
2799 if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster))
2800 unitTarget->getThreatManager().setCurrentVictim(forcedVictim);
2801 }
2802
2803 if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE))
2804 unitTarget->ToCreature()->AI()->AttackStart(m_caster);
2805 }
2806
2807 void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
2808 {
2809 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
2810 return;
2811
2812 if (!unitTarget || !unitTarget->IsAlive())
2813 return;
2814
2815 // multiple weapon dmg effect workaround
2816 // execute only the last weapon damage
2817 // and handle all effects at once
2818 for (uint8 index = effIndex + 1; index < MAX_SPELL_EFFECTS; ++index)
2819 {
2820 SpellEffectInfo const* effect = GetEffect(index);
2821 if (!effect)
2822 continue;
2823 switch (effect->Effect)
2824 {
2825 case SPELL_EFFECT_WEAPON_DAMAGE:
2826 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2827 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2828 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2829 return; // we must calculate only at last weapon effect
2830 break;
2831 }
2832 }
2833
2834 // some spell specific modifiers
2835 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
2836 int32 fixed_bonus = 0;
2837 int32 spell_bonus = 0; // bonus specific for spell
2838
2839 switch (m_spellInfo->SpellFamilyName)
2840 {
2841 case SPELLFAMILY_WARRIOR:
2842 {
2843 // Devastate (player ones)
2844 if (m_spellInfo->SpellFamilyFlags[1] & 0x40)
2845 {
2846 // Player can apply only 58567 Sunder Armor effect.
2847 bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID());
2848 if (needCast)
2849 m_caster->CastSpell(unitTarget, 58567, true);
2850
2851 if (Aura* aur = unitTarget->GetAura(58567, m_caster->GetGUID()))
2852 {
2853 if (int32 num = (needCast ? 0 : 1))
2854 aur->ModStackAmount(num);
2855 fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget);
2856 }
2857 }
2858 break;
2859 }
2860 case SPELLFAMILY_ROGUE:
2861 {
2862 // Hemorrhage
2863 if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
2864 {
2865 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2866 m_caster->ToPlayer()->AddComboPoints(1, this);
2867 // 50% more damage with daggers
2868 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2869 if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true))
2870 if (item->GetTemplate()->GetSubClass() == ITEM_SUBCLASS_WEAPON_DAGGER)
2871 totalDamagePercentMod *= 1.5f;
2872 }
2873 break;
2874 }
2875 case SPELLFAMILY_SHAMAN:
2876 {
2877 // Skyshatter Harness item set bonus
2878 // Stormstrike
2879 if (AuraEffect* aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634))
2880 m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff);
2881 break;
2882 }
2883 case SPELLFAMILY_DRUID:
2884 {
2885 // Mangle (Cat): CP
2886 if (m_spellInfo->SpellFamilyFlags[1] & 0x400)
2887 {
2888 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2889 m_caster->ToPlayer()->AddComboPoints(1, this);
2890 }
2891 break;
2892 }
2893 case SPELLFAMILY_HUNTER:
2894 {
2895 // Kill Shot - bonus damage from Ranged Attack Power
2896 if (m_spellInfo->SpellFamilyFlags[1] & 0x800000)
2897 spell_bonus += int32(0.45f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK));
2898 break;
2899 }
2900 case SPELLFAMILY_DEATHKNIGHT:
2901 {
2902 // Blood Strike
2903 if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
2904 {
2905 if (SpellEffectInfo const* effect = GetEffect(EFFECT_2))
2906 {
2907 float bonusPct = effect->CalcValue(m_caster) * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f;
2908 // Death Knight T8 Melee 4P Bonus
2909 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0))
2910 AddPct(bonusPct, aurEff->GetAmount());
2911 AddPct(totalDamagePercentMod, bonusPct);
2912 }
2913 break;
2914 }
2915 break;
2916 }
2917 }
2918
2919 bool normalized = false;
2920 float weaponDamagePercentMod = 1.0f;
2921 for (SpellEffectInfo const* effect : GetEffects())
2922 {
2923 if (!effect)
2924 continue;
2925 switch (effect->Effect)
2926 {
2927 case SPELL_EFFECT_WEAPON_DAMAGE:
2928 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2929 fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget);
2930 break;
2931 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2932 fixed_bonus += CalculateDamage(effect->EffectIndex, unitTarget);
2933 normalized = true;
2934 break;
2935 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2936 ApplyPct(weaponDamagePercentMod, CalculateDamage(effect->EffectIndex, unitTarget));
2937 break;
2938 default:
2939 break; // not weapon damage effect, just skip
2940 }
2941 }
2942
2943 // if (addPctMods) { percent mods are added in Unit::CalculateDamage } else { percent mods are added in Unit::MeleeDamageBonusDone }
2944 // this distinction is neccessary to properly inform the client about his autoattack damage values from Script_UnitDamage
2945 bool const addPctMods = !m_spellInfo->HasAttribute(SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS) && (m_spellSchoolMask & SPELL_SCHOOL_MASK_NORMAL);
2946 if (addPctMods)
2947 {
2948 UnitMods unitMod;
2949 switch (m_attackType)
2950 {
2951 default:
2952 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
2953 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
2954 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
2955 }
2956
2957 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
2958 if (fixed_bonus)
2959 fixed_bonus = int32(fixed_bonus * weapon_total_pct);
2960 if (spell_bonus)
2961 spell_bonus = int32(spell_bonus * weapon_total_pct);
2962 }
2963
2964 int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, addPctMods);
2965
2966 // Sequence is important
2967 for (SpellEffectInfo const* effect : GetEffects())
2968 {
2969 if (!effect)
2970 continue;
2971 // We assume that a spell have at most one fixed_bonus
2972 // and at most one weaponDamagePercentMod
2973 switch (effect->Effect)
2974 {
2975 case SPELL_EFFECT_WEAPON_DAMAGE:
2976 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
2977 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
2978 weaponDamage += fixed_bonus;
2979 break;
2980 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
2981 weaponDamage = int32(weaponDamage * weaponDamagePercentMod);
2982 default:
2983 break; // not weapon damage effect, just skip
2984 }
2985 }
2986
2987 weaponDamage += spell_bonus;
2988 weaponDamage = int32(weaponDamage * totalDamagePercentMod);
2989
2990 // prevent negative damage
2991 uint32 eff_damage(std::max(weaponDamage, 0));
2992
2993 // Add melee damage bonuses (also check for negative)
2994 uint32 damageBonusDone = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo);
2995
2996 m_damage += unitTarget->MeleeDamageBonusTaken(m_caster, damageBonusDone, m_attackType, m_spellInfo);
2997 }
2998
2999 void Spell::EffectThreat(SpellEffIndex /*effIndex*/)
3000 {
3001 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3002 return;
3003
3004 if (!unitTarget || !unitTarget->IsAlive() || !m_caster->IsAlive())
3005 return;
3006
3007 if (!unitTarget->CanHaveThreatList())
3008 return;
3009
3010 unitTarget->AddThreat(m_caster, float(damage));
3011 }
3012
3013 void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
3014 {
3015 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3016 return;
3017
3018 if (!unitTarget || !unitTarget->IsAlive())
3019 return;
3020
3021 int32 addhealth = 0;
3022
3023 // damage == 0 - heal for caster max health
3024 if (damage == 0)
3025 addhealth = m_caster->GetMaxHealth();
3026 else
3027 addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
3028
3029 m_healing += addhealth;
3030 }
3031
3032 void Spell::EffectInterruptCast(SpellEffIndex effIndex)
3033 {
3034 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
3035 return;
3036
3037 if (!unitTarget || !unitTarget->IsAlive())
3038 return;
3039
3040 /// @todo not all spells that used this effect apply cooldown at school spells
3041 // also exist case: apply cooldown to interrupted cast only and to all spells
3042 // there is no CURRENT_AUTOREPEAT_SPELL spells that can be interrupted
3043 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_AUTOREPEAT_SPELL; ++i)
3044 {
3045 if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i)))
3046 {
3047 SpellInfo const* curSpellInfo = spell->m_spellInfo;
3048 // check if we can interrupt spell
3049 if ((spell->getState() == SPELL_STATE_CASTING
3050 || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f))
3051 && (curSpellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
3052 && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT)
3053 || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->HasChannelInterruptFlag(CHANNEL_INTERRUPT_FLAG_INTERRUPT))))
3054 {
3055 if (m_originalCaster)
3056 {
3057 int32 duration = m_spellInfo->GetDuration();
3058 unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
3059 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);
3060 }
3061 ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
3062 unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
3063 }
3064 }
3065 }
3066 }
3067
3068 void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
3069 {
3070 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
3071 return;
3072
3073 WorldObject* target = focusObject;
3074 if (!target)
3075 target = m_caster;
3076
3077 float x, y, z;
3078 if (m_targets.HasDst())
3079 destTarget->GetPosition(x, y, z);
3080 else
3081 m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
3082
3083 Map* map = target->GetMap();
3084 Position pos = Position(x, y, z, target->GetOrientation());
3085 QuaternionData rot = QuaternionData::fromEulerAnglesZYX(target->GetOrientation(), 0.f, 0.f);
3086 GameObject* go = GameObject::CreateGameObject(effectInfo->MiscValue, map, pos, rot, 255, GO_STATE_READY);
3087 if (!go)
3088 return;
3089
3090 PhasingHandler::InheritPhaseShift(go, m_caster);
3091
3092 int32 duration = m_spellInfo->CalcDuration(m_caster);
3093
3094 go->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
3095 go->SetSpellId(m_spellInfo->Id);
3096
3097 ExecuteLogEffectSummonObject(effIndex, go);
3098
3099 // Wild object not have owner and check clickable by players
3100 map->AddToMap(go);
3101
3102 if (go->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP)
3103 if (Player* player = m_caster->ToPlayer())
3104 if (Battleground* bg = player->GetBattleground())
3105 bg->SetDroppedFlagGUID(go->GetGUID(), player->GetTeam() == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE);
3106
3107 if (GameObject* linkedTrap = go->GetLinkedTrap())
3108 {
3109 PhasingHandler::InheritPhaseShift(linkedTrap , m_caster);
3110
3111 linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0);
3112 linkedTrap->SetSpellId(m_spellInfo->Id);
3113
3114 ExecuteLogEffectSummonObject(effIndex, linkedTrap);
3115 }
3116 }
3117
3118 void Spell::EffectScriptEffect(SpellEffIndex effIndex)
3119 {
3120 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3121 return;
3122
3123 /// @todo we must implement hunter pet summon at login there (spell 6962)
3124
3125 switch (m_spellInfo->SpellFamilyName)
3126 {
3127 case SPELLFAMILY_GENERIC:
3128 {
3129 switch (m_spellInfo->Id)
3130 {
3131 case 55693: // Remove Collapsing Cave Aura
3132 if (!unitTarget)
3133 return;
3134 unitTarget->RemoveAurasDueToSpell(effectInfo->CalcValue());
3135 break;
3136 // Bending Shinbone
3137 case 8856:
3138 {
3139 if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
3140 return;
3141
3142 uint32 spell_id = roll_chance_i(20) ? 8854 : 8855;
3143
3144 m_caster->CastSpell(m_caster, spell_id, true, NULL);
3145 return;
3146 }
3147 // Brittle Armor - need remove one 24575 Brittle Armor aura
3148 case 24590:
3149 unitTarget->RemoveAuraFromStack(24575);
3150 return;
3151 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
3152 case 26465:
3153 unitTarget->RemoveAuraFromStack(26464);
3154 return;
3155 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
3156 case 22539:
3157 case 22972:
3158 case 22975:
3159 case 22976:
3160 case 22977:
3161 case 22978:
3162 case 22979:
3163 case 22980:
3164 case 22981:
3165 case 22982:
3166 case 22983:
3167 case 22984:
3168 case 22985:
3169 {
3170 if (!unitTarget || !unitTarget->IsAlive())
3171 return;
3172
3173 // Onyxia Scale Cloak
3174 if (unitTarget->HasAura(22683))
3175 return;
3176
3177 // Shadow Flame
3178 m_caster->CastSpell(unitTarget, 22682, true);
3179 return;
3180 }
3181 // Mirren's Drinking Hat
3182 case 29830:
3183 {
3184 uint32 item = 0;
3185 switch (urand(1, 6))
3186 {
3187 case 1:
3188 case 2:
3189 case 3:
3190 item = 23584; break; // Loch Modan Lager
3191 case 4:
3192 case 5:
3193 item = 23585; break; // Stouthammer Lite
3194 case 6:
3195 item = 23586; break; // Aerie Peak Pale Ale
3196 }
3197 if (item)
3198 DoCreateItem(effIndex, item);
3199 break;
3200 }
3201 case 20589: // Escape artist
3202 case 30918: // Improved Sprint
3203 {
3204 // Removes snares and roots.
3205 unitTarget->RemoveMovementImpairingAuras();
3206 break;
3207 }
3208 // Plant Warmaul Ogre Banner
3209 case 32307:
3210 if (Player* caster = m_caster->ToPlayer())
3211 {
3212 caster->RewardPlayerAndGroupAtEvent(18388, unitTarget);
3213 if (Creature* target = unitTarget->ToCreature())
3214 {
3215 target->setDeathState(CORPSE);
3216 target->RemoveCorpse();
3217 }
3218 }
3219 break;
3220 // Mug Transformation
3221 case 41931:
3222 {
3223 if (m_caster->GetTypeId() != TYPEID_PLAYER)
3224 return;
3225
3226 uint8 bag = 19;
3227 uint8 slot = 0;
3228 Item* item = NULL;
3229
3230 while (bag) // 256 = 0 due to var type
3231 {
3232 item = m_caster->ToPlayer()->GetItemByPos(bag, slot);
3233 if (item && item->GetEntry() == 38587)
3234 break;
3235
3236 ++slot;
3237 if (slot == 39)
3238 {
3239 slot = 0;
3240 ++bag;
3241 }
3242 }
3243 if (bag)
3244 {
3245 if (m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag, slot, true);
3246 else m_caster->ToPlayer()->GetItemByPos(bag, slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount()-1);
3247 // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
3248 m_caster->CastSpell(m_caster, 42518, true);
3249 return;
3250 }
3251 break;
3252 }
3253 // Brutallus - Burn
3254 case 45141:
3255 case 45151:
3256 {
3257 //Workaround for Range ... should be global for every ScriptEffect
3258 float radius = effectInfo->CalcRadius();
3259 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster)
3260 unitTarget->CastSpell(unitTarget, 46394, true);
3261
3262 break;
3263 }
3264 // Goblin Weather Machine
3265 case 46203:
3266 {
3267 if (!unitTarget)
3268 return;
3269
3270 uint32 spellId = 0;
3271 switch (rand32() % 4)
3272 {
3273 case 0: spellId = 46740; break;
3274 case 1: spellId = 46739; break;
3275 case 2: spellId = 46738; break;
3276 case 3: spellId = 46736; break;
3277 }
3278 unitTarget->CastSpell(unitTarget, spellId, true);
3279 break;
3280 }
3281 // 5, 000 Gold
3282 case 46642:
3283 {
3284 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3285 return;
3286
3287 unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD);
3288
3289 break;
3290 }
3291 // Death Knight Initiate Visual
3292 case 51519:
3293 {
3294 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
3295 return;
3296
3297 uint32 iTmpSpellId = 0;
3298 switch (unitTarget->GetDisplayId())
3299 {
3300 case 25369: iTmpSpellId = 51552; break; // bloodelf female
3301 case 25373: iTmpSpellId = 51551; break; // bloodelf male
3302 case 25363: iTmpSpellId = 51542; break; // draenei female
3303 case 25357: iTmpSpellId = 51541; break; // draenei male
3304 case 25361: iTmpSpellId = 51537; break; // dwarf female
3305 case 25356: iTmpSpellId = 51538; break; // dwarf male
3306 case 25372: iTmpSpellId = 51550; break; // forsaken female
3307 case 25367: iTmpSpellId = 51549; break; // forsaken male
3308 case 25362: iTmpSpellId = 51540; break; // gnome female
3309 case 25359: iTmpSpellId = 51539; break; // gnome male
3310 case 25355: iTmpSpellId = 51534; break; // human female
3311 case 25354: iTmpSpellId = 51520; break; // human male
3312 case 25360: iTmpSpellId = 51536; break; // nightelf female
3313 case 25358: iTmpSpellId = 51535; break; // nightelf male
3314 case 25368: iTmpSpellId = 51544; break; // orc female
3315 case 25364: iTmpSpellId = 51543; break; // orc male
3316 case 25371: iTmpSpellId = 51548; break; // tauren female
3317 case 25366: iTmpSpellId = 51547; break; // tauren male
3318 case 25370: iTmpSpellId = 51545; break; // troll female
3319 case 25365: iTmpSpellId = 51546; break; // troll male
3320 default: return;
3321 }
3322
3323 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
3324 Creature* npc = unitTarget->ToCreature();
3325 npc->LoadEquipment();
3326 return;
3327 }
3328 // Deathbolt from Thalgran Blightbringer
3329 // reflected by Freya's Ward
3330 // Retribution by Sevenfold Retribution
3331 case 51854:
3332 {
3333 if (!unitTarget)
3334 return;
3335 if (unitTarget->HasAura(51845))
3336 unitTarget->CastSpell(m_caster, 51856, true);
3337 else
3338 m_caster->CastSpell(unitTarget, 51855, true);
3339 break;
3340 }
3341 // Summon Ghouls On Scarlet Crusade
3342 case 51904:
3343 {
3344 if (!m_targets.HasDst())
3345 return;
3346
3347 float x, y, z;
3348 float radius = effectInfo->CalcRadius();
3349 for (uint8 i = 0; i < 15; ++i)
3350 {
3351 m_caster->GetRandomPoint(*destTarget, radius, x, y, z);
3352 m_caster->CastSpell(x, y, z, 54522, true);
3353 }
3354 break;
3355 }
3356 case 52173: // Coyote Spirit Despawn
3357 case 60243: // Blood Parrot Despawn
3358 if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsSummon())
3359 unitTarget->ToTempSummon()->UnSummon();
3360 return;
3361 case 52479: // Gift of the Harvester
3362 if (unitTarget && m_originalCaster)
3363 m_originalCaster->CastSpell(unitTarget, urand(0, 1