· 7 years ago · Oct 17, 2018, 04:48 PM
1/*
2 * Copyright (C) 2008-2015 TrinityCore <http://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#include "../../../src/server/game/Anticheat/AnticheatMgr.h"
19#include "Common.h"
20#include "DatabaseEnv.h"
21#include "WorldPacket.h"
22#include "Opcodes.h"
23#include "Log.h"
24#include "UpdateMask.h"
25#include "World.h"
26#include "ObjectMgr.h"
27#include "SpellMgr.h"
28#include "Player.h"
29#include "SkillExtraItems.h"
30#include "Unit.h"
31#include "Spell.h"
32#include "DynamicObject.h"
33#include "SpellAuras.h"
34#include "SpellAuraEffects.h"
35#include "SharedDefines.h"
36#include "Pet.h"
37#include "GameObject.h"
38#include "GossipDef.h"
39#include "Creature.h"
40#include "Totem.h"
41#include "CreatureAI.h"
42#include "Battleground.h"
43#include "OutdoorPvPMgr.h"
44#include "Language.h"
45#include "SocialMgr.h"
46#include "Util.h"
47#include "TemporarySummon.h"
48#include "GridNotifiers.h"
49#include "Formulas.h"
50#include "ScriptMgr.h"
51#include "SpellHistory.h"
52#include "GameObjectAI.h"
53#include "AccountMgr.h"
54#include "InstanceScript.h"
55#include "PathGenerator.h"
56#include "ReputationMgr.h"
57
58pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
59{
60 &Spell::EffectNULL, // 0
61 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvironmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectBind, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectLeap, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectJump, // 41 SPELL_EFFECT_JUMP
102 &Spell::EffectJumpDest, // 42 SPELL_EFFECT_JUMP_DEST
103 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectUnused, // 46 SPELL_EFFECT_SPAWN clientside, unit appears as if it was just spawned
107 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectCreateRandomItem, // 59 SPELL_EFFECT_CREATE_RANDOM_ITEM create item base at spell specific loot
120 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
126 &Spell::EffectRechargeManaGem, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
127 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectUntrainTalents, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
134 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
135 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectGameObjectDamage, // 87 SPELL_EFFECT_GAMEOBJECT_DAMAGE
148 &Spell::EffectGameObjectRepair, // 88 SPELL_EFFECT_GAMEOBJECT_REPAIR
149 &Spell::EffectGameObjectSetDestructionState, // 89 SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE
150 &Spell::EffectKillCreditPersonal, // 90 SPELL_EFFECT_KILL_CREDIT Kill credit but only for single person
151 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectForceDeselect, // 93 SPELL_EFFECT_FORCE_DESELECT
154 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a)
158 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectResurrectPet, //109 SPELL_EFFECT_RESURRECT_PET
170 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectUnused, //112 SPELL_EFFECT_112
173 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPullTowards, //124 SPELL_EFFECT_PULL_TOWARDS
185 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectPlaySound, //131 SPELL_EFFECT_PLAY_SOUND sound id in misc value (SoundEntries.dbc)
192 &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
193 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergizePct, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back
199 &Spell::EffectQuestClear, //139 SPELL_EFFECT_CLEAR_QUEST Reset quest status (miscValue - quest ID)
200 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectForceCast, //141 SPELL_EFFECT_FORCE_CAST_WITH_VALUE
202 &Spell::EffectTriggerSpell, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectKnockBack, //144 SPELL_EFFECT_KNOCK_BACK_DEST
205 &Spell::EffectPullTowards, //145 SPELL_EFFECT_PULL_TOWARDS_DEST Black Hole Effect
206 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
207 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectTriggerMissileSpell, //148 SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE
209 &Spell::EffectChargeDest, //149 SPELL_EFFECT_CHARGE_DEST
210 &Spell::EffectQuestStart, //150 SPELL_EFFECT_QUEST_START
211 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectSummonRaFFriend, //152 SPELL_EFFECT_SUMMON_RAF_FRIEND summon Refer-a-Friend
213 &Spell::EffectCreateTamedPet, //153 SPELL_EFFECT_CREATE_TAMED_PET misc value is creature entry
214 &Spell::EffectDiscoverTaxi, //154 SPELL_EFFECT_DISCOVER_TAXI
215 &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.
216 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
217 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create item or create item template and replace by some randon spell loot item
218 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
219 &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
220 &Spell::EffectNULL, //160 SPELL_EFFECT_160 1 spell - 45534
221 &Spell::EffectSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert)
222 &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec
223 &Spell::EffectNULL, //163 unused
224 &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA
225};
226
227void Spell::EffectNULL(SpellEffIndex /*effIndex*/)
228{
229 TC_LOG_DEBUG("spells", "WORLD: Spell Effect DUMMY");
230}
231
232void Spell::EffectUnused(SpellEffIndex /*effIndex*/)
233{
234 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN TRINITY
235}
236
237void Spell::EffectResurrectNew(SpellEffIndex effIndex)
238{
239 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
240 return;
241
242 if (!unitTarget || unitTarget->IsAlive())
243 return;
244
245 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
246 return;
247
248 if (!unitTarget->IsInWorld())
249 return;
250
251 Player* target = unitTarget->ToPlayer();
252
253 if (target->isResurrectRequested()) // already have one active request
254 return;
255
256 uint32 health = damage;
257 uint32 mana = m_spellInfo->Effects[effIndex].MiscValue;
258 ExecuteLogEffectResurrect(effIndex, target);
259 target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
260 SendResurrectRequest(target);
261}
262
263void Spell::EffectInstaKill(SpellEffIndex /*effIndex*/)
264{
265 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
266 return;
267
268 if (!unitTarget || !unitTarget->IsAlive())
269 return;
270
271 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
272 if (unitTarget->ToPlayer()->GetCommandStatus(CHEAT_GOD))
273 return;
274
275 if (m_caster == unitTarget) // prevent interrupt message
276 finish();
277
278 WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8+8+4);
279 data << uint64(m_caster->GetGUID());
280 data << uint64(unitTarget->GetGUID());
281 data << uint32(m_spellInfo->Id);
282 m_caster->SendMessageToSet(&data, true);
283
284 m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
285}
286
287void Spell::EffectEnvironmentalDMG(SpellEffIndex /*effIndex*/)
288{
289 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
290 return;
291
292 if (!unitTarget || !unitTarget->IsAlive())
293 return;
294
295 uint32 absorb = 0;
296 uint32 resist = 0;
297
298 m_caster->CalcAbsorbResist(unitTarget, m_spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist, m_spellInfo);
299
300 m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_spellInfo->GetSchoolMask(), absorb, resist, false, 0, false);
301 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
302 unitTarget->ToPlayer()->EnvironmentalDamage(DAMAGE_FIRE, damage);
303}
304
305void Spell::EffectSchoolDMG(SpellEffIndex effIndex)
306{
307 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
308 return;
309
310 if (unitTarget && unitTarget->IsAlive())
311 {
312 bool apply_direct_bonus = true;
313 switch (m_spellInfo->SpellFamilyName)
314 {
315 case SPELLFAMILY_GENERIC:
316 {
317 // Meteor like spells (divided damage to targets)
318 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE))
319 {
320 uint32 count = 0;
321 for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
322 if (ihit->effectMask & (1<<effIndex))
323 ++count;
324
325 damage /= count; // divide to all targets
326 }
327
328 switch (m_spellInfo->Id) // better way to check unknown
329 {
330 // Consumption
331 case 28865:
332 damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250);
333 break;
334 // percent from health with min
335 case 25599: // Thundercrash
336 {
337 damage = unitTarget->GetHealth() / 2;
338 if (damage < 200)
339 damage = 200;
340 break;
341 }
342 // arcane charge. must only affect demons (also undead?)
343 case 45072:
344 {
345 if (unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON
346 && unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
347 return;
348 break;
349 }
350 // Gargoyle Strike
351 case 51963:
352 {
353 // about +4 base spell dmg per level
354 damage = (m_caster->getLevel() - 60) * 4 + 60;
355 break;
356 }
357 }
358 break;
359 }
360 case SPELLFAMILY_WARRIOR:
361 {
362 // Shield Slam
363 if (m_spellInfo->SpellFamilyFlags[1] & 0x200 && m_spellInfo->GetCategory() == 1209)
364 {
365 uint8 level = m_caster->getLevel();
366 uint32 block_value = m_caster->GetShieldBlockValue(uint32(float(level) * 24.5f), uint32(float(level) * 34.5f));
367 damage += int32(m_caster->ApplyEffectModifiers(m_spellInfo, effIndex, float(block_value)));
368 }
369 // Victory Rush
370 else if (m_spellInfo->SpellFamilyFlags[1] & 0x100)
371 ApplyPct(damage, m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
372 // Shockwave
373 else if (m_spellInfo->Id == 46968)
374 {
375 int32 pct = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, 2);
376 if (pct > 0)
377 damage += int32(CalculatePct(m_caster->GetTotalAttackPowerValue(BASE_ATTACK), pct));
378 break;
379 }
380 break;
381 }
382 case SPELLFAMILY_WARLOCK:
383 {
384 // Incinerate Rank 1 & 2
385 if ((m_spellInfo->SpellFamilyFlags[1] & 0x000040) && m_spellInfo->SpellIconID == 2128)
386 {
387 // Incinerate does more dmg (dmg*0.25) if the target have Immolate debuff.
388 // Check aura state for speed but aura state set not only for Immolate spell
389 if (unitTarget->HasAuraState(AURA_STATE_CONFLAGRATE))
390 {
391 if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x4, 0, 0))
392 damage += damage/4;
393 }
394 }
395 // Conflagrate - consumes Immolate or Shadowflame
396 else if (m_spellInfo->TargetAuraState == AURA_STATE_CONFLAGRATE)
397 {
398 AuraEffect const* aura = NULL; // found req. aura for damage calculation
399
400 Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
401 for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
402 {
403 // for caster applied auras only
404 if ((*i)->GetSpellInfo()->SpellFamilyName != SPELLFAMILY_WARLOCK ||
405 (*i)->GetCasterGUID() != m_caster->GetGUID())
406 continue;
407
408 // Immolate
409 if ((*i)->GetSpellInfo()->SpellFamilyFlags[0] & 0x4)
410 {
411 aura = *i; // it selected always if exist
412 break;
413 }
414
415 // Shadowflame
416 if ((*i)->GetSpellInfo()->SpellFamilyFlags[2] & 0x00000002)
417 aura = *i; // remember but wait possible Immolate as primary priority
418 }
419
420 // found Immolate or Shadowflame
421 if (aura)
422 {
423 uint32 pdamage = uint32(std::max(aura->GetAmount(), 0));
424 pdamage = m_caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount());
425 pdamage = unitTarget->SpellDamageBonusTaken(m_caster, aura->GetSpellInfo(), pdamage, DOT, aura->GetBase()->GetStackAmount());
426 uint32 pct_dir = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 1));
427 uint8 baseTotalTicks = uint8(m_caster->CalcSpellDuration(aura->GetSpellInfo()) / aura->GetSpellInfo()->Effects[EFFECT_0].Amplitude);
428 damage += int32(CalculatePct(pdamage * baseTotalTicks, pct_dir));
429
430 uint32 pct_dot = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, (effIndex + 2)) / 3;
431 m_spellValue->EffectBasePoints[1] = m_spellInfo->Effects[EFFECT_1].CalcBaseValue(int32(CalculatePct(pdamage * baseTotalTicks, pct_dot)));
432
433 apply_direct_bonus = false;
434 // Glyph of Conflagrate
435 if (!m_caster->HasAura(56235))
436 unitTarget->RemoveAurasDueToSpell(aura->GetId(), m_caster->GetGUID());
437
438 break;
439 }
440 }
441 // Shadow Bite
442 else if (m_spellInfo->SpellFamilyFlags[1] & 0x400000)
443 {
444 if (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet())
445 {
446 if (Player* owner = m_caster->GetOwner()->ToPlayer())
447 {
448 if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, 214, 0))
449 {
450 int32 bp0 = aurEff->GetId() == 54037 ? 4 : 8;
451 m_caster->CastCustomSpell(m_caster, 54425, &bp0, NULL, NULL, true);
452 }
453 }
454 }
455 }
456 break;
457 }
458 case SPELLFAMILY_PRIEST:
459 {
460 // Improved Mind Blast (Mind Blast in shadow form bonus)
461 if (m_caster->GetShapeshiftForm() == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000))
462 {
463 Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAuraEffectsByType(SPELL_AURA_ADD_FLAT_MODIFIER);
464 for (Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i)
465 {
466 if ((*i)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST &&
467 ((*i)->GetSpellInfo()->SpellIconID == 95))
468 {
469 int chance = (*i)->GetSpellInfo()->Effects[EFFECT_1].CalcValue(m_caster);
470 if (roll_chance_i(chance))
471 // Mind Trauma
472 m_caster->CastSpell(unitTarget, 48301, true, nullptr);
473 break;
474 }
475 }
476 }
477 break;
478 }
479 case SPELLFAMILY_DRUID:
480 {
481 // Ferocious Bite
482 if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[0] & 0x000800000) && m_spellInfo->SpellVisual[0] == 6587)
483 {
484 // converts each extra point of energy into ($f1+$AP/410) additional damage
485 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
486 float multiple = ap / 410 + m_spellInfo->Effects[effIndex].DamageMultiplier;
487 int32 energy = -(m_caster->ModifyPower(POWER_ENERGY, -30));
488 damage += int32(energy * multiple);
489 damage += int32(CalculatePct(m_caster->ToPlayer()->GetComboPoints() * ap, 7));
490 }
491 // Wrath
492 else if (m_spellInfo->SpellFamilyFlags[0] & 0x00000001)
493 {
494 // Improved Insect Swarm
495 if (AuraEffect const* aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
496 if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x00200000, 0, 0))
497 AddPct(damage, aurEff->GetAmount());
498 }
499 break;
500 }
501 case SPELLFAMILY_ROGUE:
502 {
503 // Envenom
504 if (m_spellInfo->SpellFamilyFlags[1] & 0x00000008)
505 {
506 if (Player* player = m_caster->ToPlayer())
507 {
508 // consume from stack dozes not more that have combo-points
509 if (uint32 combo = player->GetComboPoints())
510 {
511 // Lookup for Deadly poison (only attacker applied)
512 if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x00010000, 0, 0, m_caster->GetGUID()))
513 {
514 // count consumed deadly poison doses at target
515 bool needConsume = true;
516 uint32 spellId = aurEff->GetId();
517
518 uint32 doses = aurEff->GetBase()->GetStackAmount();
519 if (doses > combo)
520 doses = combo;
521
522 // Master Poisoner
523 Unit::AuraEffectList const& auraList = player->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK);
524 for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
525 {
526 if ((*iter)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellInfo()->SpellIconID == 1960)
527 {
528 uint32 chance = (*iter)->GetSpellInfo()->Effects[EFFECT_2].CalcValue(m_caster);
529
530 if (chance && roll_chance_i(chance))
531 needConsume = false;
532
533 break;
534 }
535 }
536
537 if (needConsume)
538 for (uint32 i = 0; i < doses; ++i)
539 unitTarget->RemoveAuraFromStack(spellId, m_caster->GetGUID());
540
541 damage *= doses;
542 damage += int32(player->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * combo);
543 }
544
545 // Eviscerate and Envenom Bonus Damage (item set effect)
546 if (m_caster->HasAura(37169))
547 damage += combo * 40;
548 }
549 }
550 }
551 // Eviscerate
552 else if (m_spellInfo->SpellFamilyFlags[0] & 0x00020000)
553 {
554 if (Player* player = m_caster->ToPlayer())
555 {
556 if (uint32 combo = player->GetComboPoints())
557 {
558 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
559 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
560
561 // Eviscerate and Envenom Bonus Damage (item set effect)
562 if (m_caster->HasAura(37169))
563 damage += combo*40;
564 }
565 }
566 }
567 break;
568 }
569 case SPELLFAMILY_HUNTER:
570 {
571 //Gore
572 if (m_spellInfo->SpellIconID == 1578)
573 {
574 if (m_caster->HasAura(57627)) // Charge 6 sec post-affect
575 damage *= 2;
576 }
577 // Steady Shot
578 else if (m_spellInfo->SpellFamilyFlags[1] & 0x1)
579 {
580 bool found = false;
581 // check dazed affect
582 Unit::AuraEffectList const& decSpeedList = unitTarget->GetAuraEffectsByType(SPELL_AURA_MOD_DECREASE_SPEED);
583 for (Unit::AuraEffectList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
584 {
585 if ((*iter)->GetSpellInfo()->SpellIconID == 15 && (*iter)->GetSpellInfo()->Dispel == 0)
586 {
587 found = true;
588 break;
589 }
590 }
591
592 /// @todo should this be put on taken but not done?
593 if (found)
594 damage += m_spellInfo->Effects[EFFECT_1].CalcValue();
595
596 if (Player* caster = m_caster->ToPlayer())
597 {
598 // Add Ammo and Weapon damage plus RAP * 0.1
599 if (Item* item = caster->GetWeaponForAttack(RANGED_ATTACK))
600 {
601 ItemTemplate const* weaponTemplate = item->GetTemplate();
602 float dmg_min = weaponTemplate->Damage[0].DamageMin;
603 float dmg_max = weaponTemplate->Damage[0].DamageMax;
604 if (dmg_max == 0.0f && dmg_min > dmg_max)
605 damage += int32(dmg_min);
606 else
607 damage += irand(int32(dmg_min), int32(dmg_max));
608 damage += int32(caster->GetAmmoDPS() * weaponTemplate->Delay * 0.001f);
609 }
610 }
611 }
612 break;
613 }
614 case SPELLFAMILY_PALADIN:
615 {
616 // Hammer of the Righteous
617 if (m_spellInfo->SpellFamilyFlags[1]&0x00040000)
618 {
619 float min_damage = m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE);
620 float max_damage = m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE);
621 if (Player* player = m_caster->ToPlayer()) // UNIT_FIELD_MINDAMAGE/MAXDAMAGE already include damage bonuses, so try to get them without damage bonuses
622 player->CalculateMinMaxDamage(BASE_ATTACK, false, false, min_damage, max_damage);
623
624 float average = (min_damage + max_damage) / 2;
625 // Add main hand dps * effect[2] amount
626 int32 count = m_caster->CalculateSpellDamage(unitTarget, m_spellInfo, EFFECT_2);
627 damage += count * int32(average * IN_MILLISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
628 break;
629 }
630 // Shield of Righteousness
631 if (m_spellInfo->SpellFamilyFlags[EFFECT_1] & 0x100000)
632 {
633 uint8 level = m_caster->getLevel();
634 uint32 block_value = m_caster->GetShieldBlockValue(uint32(float(level) * 29.5f), uint32(float(level) * 39.5f));
635 damage += CalculatePct(block_value, m_spellInfo->Effects[EFFECT_1].CalcValue());
636 break;
637 }
638 break;
639 }
640 case SPELLFAMILY_DEATHKNIGHT:
641 {
642 // Blood Boil - bonus for diseased targets
643 if (m_spellInfo->SpellFamilyFlags[0] & 0x00040000)
644 {
645 if (unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DEATHKNIGHT, 0, 0, 0x00000002, m_caster->GetGUID()))
646 {
647 damage += m_damage / 2;
648 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.035f);
649 }
650 }
651 break;
652 }
653 }
654
655 if (m_originalCaster && damage > 0 && apply_direct_bonus)
656 {
657 damage = m_originalCaster->SpellDamageBonusDone(unitTarget, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
658 damage = unitTarget->SpellDamageBonusTaken(m_originalCaster, m_spellInfo, (uint32)damage, SPELL_DIRECT_DAMAGE);
659 }
660
661 m_damage += damage;
662 }
663}
664
665void Spell::EffectDummy(SpellEffIndex effIndex)
666{
667 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
668 return;
669
670 if (!unitTarget && !gameObjTarget && !itemTarget)
671 return;
672
673 // selection by spell family
674 switch (m_spellInfo->SpellFamilyName)
675 {
676 case SPELLFAMILY_PALADIN:
677 switch (m_spellInfo->Id)
678 {
679 case 31789: // Righteous Defense (step 1)
680 {
681 // Clear targets for eff 1
682 for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
683 ihit->effectMask &= ~(1<<1);
684
685 // not empty (checked), copy
686 Unit::AttackerSet attackers = unitTarget->getAttackers();
687
688 // remove invalid attackers
689 for (Unit::AttackerSet::iterator aItr = attackers.begin(); aItr != attackers.end();)
690 if (!(*aItr)->IsValidAttackTarget(m_caster))
691 attackers.erase(aItr++);
692 else
693 ++aItr;
694
695 // selected from list 3
696 uint32 maxTargets = std::min<uint32>(3, attackers.size());
697 for (uint32 i = 0; i < maxTargets; ++i)
698 {
699 Unit* attacker = Trinity::Containers::SelectRandomContainerElement(attackers);
700 AddUnitTarget(attacker, 1 << 1);
701 attackers.erase(attacker);
702 }
703
704 // now let next effect cast spell at each target.
705 return;
706 }
707 }
708 break;
709 default:
710 break;
711 }
712
713 // pet auras
714 if (PetAura const* petSpell = sSpellMgr->GetPetAura(m_spellInfo->Id, effIndex))
715 {
716 m_caster->AddPetAura(petSpell);
717 return;
718 }
719
720 // normal DB scripted effect
721 TC_LOG_DEBUG("spells", "Spell ScriptStart spellid %u in EffectDummy(%u)", m_spellInfo->Id, effIndex);
722 m_caster->GetMap()->ScriptsStart(sSpellScripts, uint32(m_spellInfo->Id | (effIndex << 24)), m_caster, unitTarget);
723
724 // Script based implementation. Must be used only for not good for implementation in core spell effects
725 // So called only for not proccessed cases
726 if (gameObjTarget)
727 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, gameObjTarget);
728 else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
729 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, unitTarget->ToCreature());
730 else if (itemTarget)
731 sScriptMgr->OnDummyEffect(m_caster, m_spellInfo->Id, effIndex, itemTarget);
732}
733
734void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
735{
736 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET
737 && effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
738 return;
739
740 uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell;
741
742 /// @todo move those to spell scripts
743 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_SPELL
744 && effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
745 {
746 // special cases
747 switch (triggered_spell_id)
748 {
749 // Mirror Image
750 case 58832:
751 {
752 // Glyph of Mirror Image
753 if (m_caster->HasAura(63093))
754 m_caster->CastSpell(m_caster, 65047, true); // Mirror Image
755
756 break;
757 }
758 // Vanish (not exist)
759 case 18461:
760 {
761 unitTarget->RemoveMovementImpairingAuras();
762 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
763
764 // If this spell is given to an NPC, it must handle the rest using its own AI
765 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
766 return;
767
768 // See if we already are stealthed. If so, we're done.
769 if (unitTarget->HasAura(1784))
770 return;
771
772 // Reset cooldown on stealth if needed
773 if (unitTarget->GetSpellHistory()->HasCooldown(1784))
774 unitTarget->GetSpellHistory()->ResetCooldown(1784);
775
776 unitTarget->CastSpell(unitTarget, 1784, true);
777 return;
778 }
779 // Demonic Empowerment -- succubus
780 case 54437:
781 {
782 unitTarget->RemoveMovementImpairingAuras();
783 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STALKED);
784 unitTarget->RemoveAurasByType(SPELL_AURA_MOD_STUN);
785
786 // Cast Lesser Invisibility
787 unitTarget->CastSpell(unitTarget, 7870, true);
788 return;
789 }
790 // just skip
791 case 23770: // Sayge's Dark Fortune of *
792 // not exist, common cooldown can be implemented in scripts if need.
793 return;
794 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
795 case 29284:
796 {
797 // Brittle Armor
798 SpellInfo const* spell = sSpellMgr->GetSpellInfo(24575);
799 if (!spell)
800 return;
801
802 for (uint32 j = 0; j < spell->StackAmount; ++j)
803 m_caster->CastSpell(unitTarget, spell->Id, true);
804 return;
805 }
806 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
807 case 29286:
808 {
809 // Mercurial Shield
810 SpellInfo const* spell = sSpellMgr->GetSpellInfo(26464);
811 if (!spell)
812 return;
813
814 for (uint32 j = 0; j < spell->StackAmount; ++j)
815 m_caster->CastSpell(unitTarget, spell->Id, true);
816 return;
817 }
818 // Cloak of Shadows
819 case 35729:
820 {
821 uint32 dispelMask = SpellInfo::GetDispelMask(DISPEL_ALL);
822 Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
823 for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();)
824 {
825 // remove all harmful spells on you...
826 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
827 if (((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC && spell->GetSchoolMask() != SPELL_SCHOOL_MASK_NORMAL) // only affect magic spells
828 || (spell->GetDispelMask() & dispelMask)) &&
829 // ignore positive and passive auras
830 !iter->second->IsPositive() && !iter->second->GetBase()->IsPassive())
831 {
832 m_caster->RemoveAura(iter);
833 }
834 else
835 ++iter;
836 }
837 return;
838 }
839 }
840 }
841
842 // normal case
843 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
844 if (!spellInfo)
845 {
846 TC_LOG_ERROR("spells", "Spell::EffectTriggerSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id);
847 return;
848 }
849
850 SpellCastTargets targets;
851 if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
852 {
853 if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo))
854 return;
855 targets.SetUnitTarget(unitTarget);
856 }
857 else //if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH)
858 {
859 if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK))
860 return;
861
862 if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
863 targets.SetDst(m_targets);
864
865 if (Unit* target = m_targets.GetUnitTarget())
866 targets.SetUnitTarget(target);
867 else
868 targets.SetUnitTarget(m_caster);
869 }
870
871 CustomSpellValues values;
872 // set basepoints for trigger with value effect
873 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE)
874 {
875 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
876 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
877 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
878 }
879
880 // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
881 if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
882 && m_spellInfo->GetCategory() == spellInfo->GetCategory())
883 m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
884
885 // original caster guid only for GO cast
886 m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
887}
888
889void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex)
890{
891 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET
892 && effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
893 return;
894
895 uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell;
896
897 // normal case
898 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
899 if (!spellInfo)
900 {
901 TC_LOG_ERROR("spells", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id);
902 return;
903 }
904
905 SpellCastTargets targets;
906 if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
907 {
908 if (!spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo))
909 return;
910 targets.SetUnitTarget(unitTarget);
911 }
912 else //if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT)
913 {
914 if (spellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) && (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & TARGET_FLAG_UNIT_MASK))
915 return;
916
917 if (spellInfo->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
918 targets.SetDst(m_targets);
919
920 targets.SetUnitTarget(m_caster);
921 }
922
923 CustomSpellValues values;
924 // set basepoints for trigger with value effect
925 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_MISSILE_SPELL_WITH_VALUE)
926 {
927 // maybe need to set value only when basepoints == 0?
928 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
929 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
930 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
931 }
932
933 // Remove spell cooldown (not category) if spell triggering spell with cooldown and same category
934 if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->CategoryRecoveryTime && spellInfo->CategoryRecoveryTime
935 && m_spellInfo->GetCategory() == spellInfo->GetCategory())
936 m_caster->GetSpellHistory()->ResetCooldown(spellInfo->Id);
937
938 // original caster guid only for GO cast
939 m_caster->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK, NULL, NULL, m_originalCasterGUID);
940}
941
942void Spell::EffectForceCast(SpellEffIndex effIndex)
943{
944 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
945 return;
946
947 if (!unitTarget)
948 return;
949
950 uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell;
951
952 // normal case
953 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
954
955 if (!spellInfo)
956 {
957 TC_LOG_ERROR("spells", "Spell::EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
958 return;
959 }
960
961 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_FORCE_CAST && damage)
962 {
963 switch (m_spellInfo->Id)
964 {
965 case 52588: // Skeletal Gryphon Escape
966 case 48598: // Ride Flamebringer Cue
967 unitTarget->RemoveAura(damage);
968 break;
969 case 52463: // Hide In Mine Car
970 case 52349: // Overtake
971 unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID);
972 return;
973 }
974 }
975
976 switch (spellInfo->Id)
977 {
978 case 72298: // Malleable Goo Summon
979 unitTarget->CastSpell(unitTarget, spellInfo->Id, true, NULL, NULL, m_originalCasterGUID);
980 return;
981 }
982
983 CustomSpellValues values;
984 // set basepoints for trigger with value effect
985 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_FORCE_CAST_WITH_VALUE)
986 {
987 // maybe need to set value only when basepoints == 0?
988 values.AddSpellMod(SPELLVALUE_BASE_POINT0, damage);
989 values.AddSpellMod(SPELLVALUE_BASE_POINT1, damage);
990 values.AddSpellMod(SPELLVALUE_BASE_POINT2, damage);
991 }
992
993 SpellCastTargets targets;
994 targets.SetUnitTarget(m_caster);
995
996 unitTarget->CastSpell(targets, spellInfo, &values, TRIGGERED_FULL_MASK);
997}
998
999void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex effIndex)
1000{
1001 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1002 return;
1003
1004 uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell;
1005 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id);
1006
1007 if (!spellInfo)
1008 {
1009 TC_LOG_ERROR("spells", "EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id);
1010 return;
1011 }
1012
1013 finish();
1014
1015 m_caster->CastSpell((Unit*)NULL, spellInfo, false);
1016}
1017
1018void Spell::EffectJump(SpellEffIndex effIndex)
1019{
1020 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
1021 return;
1022
1023 if (m_caster->IsInFlight())
1024 return;
1025
1026 if (!unitTarget)
1027 return;
1028
1029 float x, y, z;
1030 unitTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE);
1031
1032 float speedXY, speedZ;
1033 CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(x, y), speedXY, speedZ);
1034 m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
1035}
1036
1037void Spell::EffectJumpDest(SpellEffIndex effIndex)
1038{
1039 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
1040 return;
1041
1042 if (m_caster->IsInFlight())
1043 return;
1044
1045 if (!m_targets.HasDst())
1046 return;
1047
1048 // Init dest coordinates
1049 float x, y, z;
1050 destTarget->GetPosition(x, y, z);
1051
1052 float speedXY, speedZ;
1053 CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(x, y), speedXY, speedZ);
1054 m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
1055}
1056
1057void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ)
1058{
1059 if (m_spellInfo->Effects[i].MiscValue)
1060 speedZ = float(m_spellInfo->Effects[i].MiscValue)/10;
1061 else if (m_spellInfo->Effects[i].MiscValueB)
1062 speedZ = float(m_spellInfo->Effects[i].MiscValueB)/10;
1063 else
1064 speedZ = 10.0f;
1065 speedXY = dist * 10.0f / speedZ;
1066}
1067
1068void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
1069{
1070 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1071 return;
1072
1073 if (!unitTarget || unitTarget->IsInFlight())
1074 return;
1075
1076 // If not exist data for dest location - return
1077 if (!m_targets.HasDst())
1078 {
1079 TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id);
1080 return;
1081 }
1082
1083 // Init dest coordinates
1084 uint32 mapid = destTarget->GetMapId();
1085 if (mapid == MAPID_INVALID)
1086 mapid = unitTarget->GetMapId();
1087 float x, y, z, orientation;
1088 destTarget->GetPosition(x, y, z, orientation);
1089 if (!orientation && m_targets.GetUnitTarget())
1090 orientation = m_targets.GetUnitTarget()->GetOrientation();
1091 TC_LOG_DEBUG("spells", "Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation);
1092
1093 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
1094 unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL | TELE_TO_NOT_LEAVE_COMBAT : 0);
1095 else if (mapid == unitTarget->GetMapId())
1096 unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
1097 else
1098 {
1099 TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - spellId %u attempted to teleport creature to a different map.", m_spellInfo->Id);
1100 return;
1101 }
1102
1103 // post effects for TARGET_DEST_DB
1104 switch (m_spellInfo->Id)
1105 {
1106 // Dimensional Ripper - Everlook
1107 case 23442:
1108 {
1109 int32 r = irand(0, 119);
1110 if (r >= 70) // 7/12 success
1111 {
1112 if (r < 100) // 4/12 evil twin
1113 m_caster->CastSpell(m_caster, 23445, true);
1114 else // 1/12 fire
1115 m_caster->CastSpell(m_caster, 23449, true);
1116 }
1117 return;
1118 }
1119 // Ultrasafe Transporter: Toshley's Station
1120 case 36941:
1121 {
1122 if (roll_chance_i(50)) // 50% success
1123 {
1124 int32 rand_eff = urand(1, 7);
1125 switch (rand_eff)
1126 {
1127 case 1:
1128 // soul split - evil
1129 m_caster->CastSpell(m_caster, 36900, true);
1130 break;
1131 case 2:
1132 // soul split - good
1133 m_caster->CastSpell(m_caster, 36901, true);
1134 break;
1135 case 3:
1136 // Increase the size
1137 m_caster->CastSpell(m_caster, 36895, true);
1138 break;
1139 case 4:
1140 // Decrease the size
1141 m_caster->CastSpell(m_caster, 36893, true);
1142 break;
1143 case 5:
1144 // Transform
1145 {
1146 if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
1147 m_caster->CastSpell(m_caster, 36897, true);
1148 else
1149 m_caster->CastSpell(m_caster, 36899, true);
1150 break;
1151 }
1152 case 6:
1153 // chicken
1154 m_caster->CastSpell(m_caster, 36940, true);
1155 break;
1156 case 7:
1157 // evil twin
1158 m_caster->CastSpell(m_caster, 23445, true);
1159 break;
1160 }
1161 }
1162 return;
1163 }
1164 // Dimensional Ripper - Area 52
1165 case 36890:
1166 {
1167 if (roll_chance_i(50)) // 50% success
1168 {
1169 int32 rand_eff = urand(1, 4);
1170 switch (rand_eff)
1171 {
1172 case 1:
1173 // soul split - evil
1174 m_caster->CastSpell(m_caster, 36900, true);
1175 break;
1176 case 2:
1177 // soul split - good
1178 m_caster->CastSpell(m_caster, 36901, true);
1179 break;
1180 case 3:
1181 // Increase the size
1182 m_caster->CastSpell(m_caster, 36895, true);
1183 break;
1184 case 4:
1185 // Transform
1186 {
1187 if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
1188 m_caster->CastSpell(m_caster, 36897, true);
1189 else
1190 m_caster->CastSpell(m_caster, 36899, true);
1191 break;
1192 }
1193 }
1194 }
1195 return;
1196 }
1197 }
1198}
1199
1200void Spell::EffectApplyAura(SpellEffIndex effIndex)
1201{
1202 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1203 return;
1204
1205 if (!m_spellAura || !unitTarget)
1206 return;
1207 ASSERT(unitTarget == m_spellAura->GetOwner());
1208 m_spellAura->_ApplyEffectForTargets(effIndex);
1209}
1210
1211void Spell::EffectApplyAreaAura(SpellEffIndex effIndex)
1212{
1213 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1214 return;
1215
1216 if (!m_spellAura || !unitTarget)
1217 return;
1218 ASSERT (unitTarget == m_spellAura->GetOwner());
1219 m_spellAura->_ApplyEffectForTargets(effIndex);
1220}
1221
1222void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex)
1223{
1224 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1225 return;
1226
1227 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1228 return;
1229
1230 Player* player = unitTarget->ToPlayer();
1231 uint32 spellToUnlearn = m_spellInfo->Effects[effIndex].TriggerSpell;
1232
1233 player->RemoveSpell(spellToUnlearn);
1234
1235 TC_LOG_DEBUG("spells", "Spell: Player %u has unlearned spell %u from NpcGUID: %u", player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow());
1236}
1237
1238void Spell::EffectPowerDrain(SpellEffIndex effIndex)
1239{
1240 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1241 return;
1242
1243 if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS))
1244 return;
1245
1246 Powers powerType = Powers(m_spellInfo->Effects[effIndex].MiscValue);
1247
1248 if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != powerType || damage < 0)
1249 return;
1250
1251 // add spell damage bonus
1252 damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
1253 damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
1254
1255 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
1256 int32 power = damage;
1257 if (powerType == POWER_MANA)
1258 power -= unitTarget->GetSpellCritDamageReduction(power);
1259
1260 int32 newDamage = -(unitTarget->ModifyPower(powerType, -int32(power)));
1261
1262 float gainMultiplier = 0.0f;
1263
1264 // Don't restore from self drain
1265 if (m_caster != unitTarget)
1266 {
1267 gainMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this);
1268
1269 int32 gain = int32(newDamage* gainMultiplier);
1270
1271 m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, powerType);
1272 }
1273 ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, gainMultiplier);
1274}
1275
1276void Spell::EffectSendEvent(SpellEffIndex effIndex)
1277{
1278 // we do not handle a flag dropping or clicking on flag in battleground by sendevent system
1279 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET
1280 && effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1281 return;
1282
1283 WorldObject* target = NULL;
1284
1285 // call events for object target if present
1286 if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
1287 {
1288 if (unitTarget)
1289 target = unitTarget;
1290 else if (gameObjTarget)
1291 target = gameObjTarget;
1292 }
1293 else // if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT)
1294 {
1295 // let's prevent executing effect handler twice in case when spell effect is capable of targeting an object
1296 // this check was requested by scripters, but it has some downsides:
1297 // now it's impossible to script (using sEventScripts) a cast which misses all targets
1298 // or to have an ability to script the moment spell hits dest (in a case when there are object targets present)
1299 if (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK))
1300 return;
1301 // some spells have no target entries in dbc and they use focus target
1302 if (focusObject)
1303 target = focusObject;
1304 /// @todo there should be a possibility to pass dest target to event script
1305 }
1306
1307 TC_LOG_DEBUG("spells", "Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id);
1308
1309 if (ZoneScript* zoneScript = m_caster->GetZoneScript())
1310 zoneScript->ProcessEvent(target, m_spellInfo->Effects[effIndex].MiscValue);
1311 else if (InstanceScript* instanceScript = m_caster->GetInstanceScript()) // needed in case Player is the caster
1312 instanceScript->ProcessEvent(target, m_spellInfo->Effects[effIndex].MiscValue);
1313
1314 m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->Effects[effIndex].MiscValue, m_caster, target);
1315}
1316
1317void Spell::EffectPowerBurn(SpellEffIndex effIndex)
1318{
1319 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1320 return;
1321
1322 if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS))
1323 return;
1324
1325 Powers powerType = Powers(m_spellInfo->Effects[effIndex].MiscValue);
1326
1327 if (!unitTarget || !unitTarget->IsAlive() || unitTarget->getPowerType() != powerType || damage < 0)
1328 return;
1329
1330 // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
1331 if (m_spellInfo->Id == 8129)
1332 {
1333 int32 maxDamage = int32(CalculatePct(m_caster->GetMaxPower(powerType), damage * 2));
1334 damage = int32(CalculatePct(unitTarget->GetMaxPower(powerType), damage));
1335 damage = std::min(damage, maxDamage);
1336 }
1337
1338 int32 power = damage;
1339 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
1340 if (powerType == POWER_MANA)
1341 power -= unitTarget->GetSpellCritDamageReduction(power);
1342
1343 int32 newDamage = -(unitTarget->ModifyPower(powerType, -power));
1344
1345 // NO - Not a typo - EffectPowerBurn uses effect value multiplier - not effect damage multiplier
1346 float dmgMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this);
1347
1348 // add log data before multiplication (need power amount, not damage)
1349 ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, 0.0f);
1350
1351 newDamage = int32(newDamage* dmgMultiplier);
1352
1353 m_damage += newDamage;
1354}
1355
1356void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
1357{
1358 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
1359 return;
1360
1361 if (unitTarget && unitTarget->IsAlive() && damage >= 0)
1362 {
1363 // Try to get original caster
1364 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
1365
1366 // Skip if m_originalCaster not available
1367 if (!caster)
1368 return;
1369
1370 int32 addhealth = damage;
1371
1372 // Vessel of the Naaru (Vial of the Sunwell trinket)
1373 if (m_spellInfo->Id == 45064)
1374 {
1375 // Amount of heal - depends from stacked Holy Energy
1376 int damageAmount = 0;
1377 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(45062, 0))
1378 {
1379 damageAmount+= aurEff->GetAmount();
1380 m_caster->RemoveAurasDueToSpell(45062);
1381 }
1382
1383 addhealth += damageAmount;
1384 }
1385 // Runic Healing Injector (heal increased by 25% for engineers - 3.2.0 patch change)
1386 else if (m_spellInfo->Id == 67489)
1387 {
1388 if (Player* player = m_caster->ToPlayer())
1389 if (player->HasSkill(SKILL_ENGINEERING))
1390 AddPct(addhealth, 25);
1391 }
1392 // Swiftmend - consumes Regrowth or Rejuvenation
1393 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster))
1394 {
1395 Unit::AuraEffectList const& RejorRegr = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
1396 // find most short by duration
1397 AuraEffect* targetAura = NULL;
1398 for (Unit::AuraEffectList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
1399 {
1400 if ((*i)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID
1401 && (*i)->GetSpellInfo()->SpellFamilyFlags[0] & 0x50)
1402 {
1403 if (!targetAura || (*i)->GetBase()->GetDuration() < targetAura->GetBase()->GetDuration())
1404 targetAura = *i;
1405 }
1406 }
1407
1408 if (!targetAura)
1409 {
1410 TC_LOG_ERROR("spells", "Target (%s) has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID().ToString().c_str());
1411 return;
1412 }
1413
1414 int32 tickheal = targetAura->GetAmount();
1415 if (Unit* auraCaster = targetAura->GetCaster())
1416 tickheal = auraCaster->SpellHealingBonusDone(unitTarget, targetAura->GetSpellInfo(), tickheal, DOT);
1417 //int32 tickheal = targetAura->GetSpellInfo()->EffectBasePoints[idx] + 1;
1418 //It is said that talent bonus should not be included
1419
1420 int32 tickcount = 0;
1421 // Rejuvenation
1422 if (targetAura->GetSpellInfo()->SpellFamilyFlags[0] & 0x10)
1423 tickcount = 4;
1424 // Regrowth
1425 else // if (targetAura->GetSpellInfo()->SpellFamilyFlags[0] & 0x40)
1426 tickcount = 6;
1427
1428 addhealth += tickheal * tickcount;
1429
1430 // Glyph of Swiftmend
1431 if (!caster->HasAura(54824))
1432 unitTarget->RemoveAura(targetAura->GetId(), targetAura->GetCasterGUID());
1433
1434 //addhealth += tickheal * tickcount;
1435 //addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth, HEAL, unitTarget);
1436 }
1437 // Nourish
1438 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x2000000)
1439 {
1440 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
1441
1442 // Glyph of Nourish
1443 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(62971, 0))
1444 {
1445 Unit::AuraEffectList const& Periodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL);
1446 for (Unit::AuraEffectList::const_iterator i = Periodic.begin(); i != Periodic.end(); ++i)
1447 {
1448 if (m_caster->GetGUID() == (*i)->GetCasterGUID())
1449 AddPct(addhealth, aurEff->GetAmount());
1450 }
1451 }
1452 }
1453 // Death Pact - return pct of max health to caster
1454 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000)
1455 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, int32(caster->CountPctFromMaxHealth(damage)), HEAL);
1456 else
1457 addhealth = caster->SpellHealingBonusDone(unitTarget, m_spellInfo, addhealth, HEAL);
1458
1459 addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
1460
1461 // Remove Grievious bite if fully healed
1462 if (unitTarget->HasAura(48920) && (unitTarget->GetHealth() + addhealth >= unitTarget->GetMaxHealth()))
1463 unitTarget->RemoveAura(48920);
1464
1465 m_damage -= addhealth;
1466 }
1467}
1468
1469void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
1470{
1471 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1472 return;
1473
1474 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1475 return;
1476
1477 // Skip if m_originalCaster not available
1478 if (!m_originalCaster)
1479 return;
1480
1481 uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL);
1482 heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
1483
1484 m_healing += heal;
1485}
1486
1487void Spell::EffectHealMechanical(SpellEffIndex /*effIndex*/)
1488{
1489 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1490 return;
1491
1492 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1493 return;
1494
1495 // Skip if m_originalCaster not available
1496 if (!m_originalCaster)
1497 return;
1498
1499 uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, uint32(damage), HEAL);
1500
1501 m_healing += unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
1502}
1503
1504void Spell::EffectHealthLeech(SpellEffIndex effIndex)
1505{
1506 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1507 return;
1508
1509 if (!unitTarget || !unitTarget->IsAlive() || damage < 0)
1510 return;
1511
1512 damage = m_caster->SpellDamageBonusDone(unitTarget, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
1513 damage = unitTarget->SpellDamageBonusTaken(m_caster, m_spellInfo, uint32(damage), SPELL_DIRECT_DAMAGE);
1514
1515 TC_LOG_DEBUG("spells", "HealthLeech :%i", damage);
1516
1517 float healMultiplier = m_spellInfo->Effects[effIndex].CalcValueMultiplier(m_originalCaster, this);
1518
1519 m_damage += damage;
1520 // get max possible damage, don't count overkill for heal
1521 uint32 healthGain = uint32(-unitTarget->GetHealthGain(-damage) * healMultiplier);
1522
1523 if (m_caster->IsAlive())
1524 {
1525 healthGain = m_caster->SpellHealingBonusDone(m_caster, m_spellInfo, healthGain, HEAL);
1526 healthGain = m_caster->SpellHealingBonusTaken(m_caster, m_spellInfo, healthGain, HEAL);
1527
1528 m_caster->HealBySpell(m_caster, m_spellInfo, uint32(healthGain));
1529 }
1530}
1531
1532void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
1533{
1534 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1535 return;
1536
1537 Player* player = unitTarget->ToPlayer();
1538
1539 uint32 newitemid = itemtype;
1540 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(newitemid);
1541 if (!pProto)
1542 {
1543 player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
1544 return;
1545 }
1546
1547 // bg reward have some special in code work
1548 uint32 bgType = 0;
1549 switch (m_spellInfo->Id)
1550 {
1551 case SPELL_AV_MARK_WINNER:
1552 case SPELL_AV_MARK_LOSER:
1553 bgType = BATTLEGROUND_AV;
1554 break;
1555 case SPELL_WS_MARK_WINNER:
1556 case SPELL_WS_MARK_LOSER:
1557 bgType = BATTLEGROUND_WS;
1558 break;
1559 case SPELL_AB_MARK_WINNER:
1560 case SPELL_AB_MARK_LOSER:
1561 bgType = BATTLEGROUND_AB;
1562 break;
1563 default:
1564 break;
1565 }
1566
1567 uint32 num_to_add = damage;
1568
1569 if (num_to_add < 1)
1570 num_to_add = 1;
1571 if (num_to_add > pProto->GetMaxStackSize())
1572 num_to_add = pProto->GetMaxStackSize();
1573
1574 // init items_count to 1, since 1 item will be created regardless of specialization
1575 int items_count=1;
1576 // the chance to create additional items
1577 float additionalCreateChance=0.0f;
1578 // the maximum number of created additional items
1579 uint8 additionalMaxNum=0;
1580 // get the chance and maximum number for creating extra items
1581 if (CanCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum))
1582 {
1583 // roll with this chance till we roll not to create or we create the max num
1584 while (roll_chance_f(additionalCreateChance) && items_count <= additionalMaxNum)
1585 ++items_count;
1586 }
1587
1588 // really will be created more items
1589 num_to_add *= items_count;
1590
1591 // can the player store the new item?
1592 ItemPosCountVec dest;
1593 uint32 no_space = 0;
1594 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space);
1595 if (msg != EQUIP_ERR_OK)
1596 {
1597 // convert to possible store amount
1598 if (msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
1599 num_to_add -= no_space;
1600 else
1601 {
1602 // if not created by another reason from full inventory or unique items amount limitation
1603 player->SendEquipError(msg, NULL, NULL, newitemid);
1604 return;
1605 }
1606 }
1607
1608 if (num_to_add)
1609 {
1610 // create the new item and store it
1611 Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
1612
1613 // was it successful? return error if not
1614 if (!pItem)
1615 {
1616 player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
1617 return;
1618 }
1619
1620 // set the "Crafted by ..." property of the item
1621 if (pItem->GetTemplate()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetTemplate()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
1622 pItem->SetGuidValue(ITEM_FIELD_CREATOR, player->GetGUID());
1623
1624 // send info to the client
1625 player->SendNewItem(pItem, num_to_add, true, bgType == 0);
1626
1627 // we succeeded in creating at least one item, so a levelup is possible
1628 if (bgType == 0)
1629 player->UpdateCraftSkill(m_spellInfo->Id);
1630 }
1631
1632/*
1633 // for battleground marks send by mail if not add all expected
1634 if (no_space > 0 && bgType)
1635 {
1636 if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BattlegroundTypeId(bgType)))
1637 bg->SendRewardMarkByMail(player, newitemid, no_space);
1638 }
1639*/
1640}
1641
1642void Spell::EffectCreateItem(SpellEffIndex effIndex)
1643{
1644 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1645 return;
1646
1647 DoCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType);
1648 ExecuteLogEffectCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType);
1649}
1650
1651void Spell::EffectCreateItem2(SpellEffIndex effIndex)
1652{
1653 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1654 return;
1655
1656 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1657 return;
1658
1659 Player* player = unitTarget->ToPlayer();
1660
1661 uint32 item_id = m_spellInfo->Effects[effIndex].ItemType;
1662
1663 if (item_id)
1664 DoCreateItem(effIndex, item_id);
1665
1666 // special case: fake item replaced by generate using spell_loot_template
1667 if (m_spellInfo->IsLootCrafting())
1668 {
1669 if (item_id)
1670 {
1671 if (!player->HasItemCount(item_id))
1672 return;
1673
1674 // remove reagent
1675 uint32 count = 1;
1676 player->DestroyItemCount(item_id, count, true);
1677
1678 // create some random items
1679 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
1680 }
1681 else
1682 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items
1683 }
1684 /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType);
1685}
1686
1687void Spell::EffectCreateRandomItem(SpellEffIndex /*effIndex*/)
1688{
1689 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1690 return;
1691
1692 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
1693 return;
1694 Player* player = unitTarget->ToPlayer();
1695
1696 // create some random items
1697 player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell);
1698 /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType);
1699}
1700
1701void Spell::EffectPersistentAA(SpellEffIndex effIndex)
1702{
1703 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
1704 return;
1705
1706 if (!m_spellAura)
1707 {
1708 Unit* caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster;
1709 float radius = m_spellInfo->Effects[effIndex].CalcRadius(caster);
1710
1711 // Caster not in world, might be spell triggered from aura removal
1712 if (!caster->IsInWorld())
1713 return;
1714 DynamicObject* dynObj = new DynamicObject(false);
1715 if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL))
1716 {
1717 delete dynObj;
1718 return;
1719 }
1720
1721 if (Aura* aura = Aura::TryCreate(m_spellInfo, MAX_EFFECT_MASK, dynObj, caster, &m_spellValue->EffectBasePoints[0]))
1722 {
1723 m_spellAura = aura;
1724 m_spellAura->_RegisterForTargets();
1725 }
1726 else
1727 return;
1728 }
1729
1730 ASSERT(m_spellAura->GetDynobjOwner());
1731 m_spellAura->_ApplyEffectForTargets(effIndex);
1732}
1733
1734void Spell::EffectEnergize(SpellEffIndex effIndex)
1735{
1736 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1737 return;
1738
1739 if (!unitTarget)
1740 return;
1741 if (!unitTarget->IsAlive())
1742 return;
1743
1744 if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS))
1745 return;
1746
1747 Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
1748
1749 if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
1750 return;
1751
1752 if (unitTarget->GetMaxPower(power) == 0)
1753 return;
1754
1755 // Some level depends spells
1756 int level_multiplier = 0;
1757 int level_diff = 0;
1758 switch (m_spellInfo->Id)
1759 {
1760 case 9512: // Restore Energy
1761 level_diff = m_caster->getLevel() - 40;
1762 level_multiplier = 2;
1763 break;
1764 case 24571: // Blood Fury
1765 level_diff = m_caster->getLevel() - 60;
1766 level_multiplier = 10;
1767 break;
1768 case 24532: // Burst of Energy
1769 level_diff = m_caster->getLevel() - 60;
1770 level_multiplier = 4;
1771 break;
1772 case 31930: // Judgements of the Wise
1773 case 63375: // Improved Stormstrike
1774 case 68082: // Glyph of Seal of Command
1775 damage = int32(CalculatePct(unitTarget->GetCreateMana(), damage));
1776 break;
1777 case 48542: // Revitalize
1778 damage = int32(CalculatePct(unitTarget->GetMaxPower(power), damage));
1779 break;
1780 case 67490: // Runic Mana Injector (mana gain increased by 25% for engineers - 3.2.0 patch change)
1781 {
1782 if (Player* player = m_caster->ToPlayer())
1783 if (player->HasSkill(SKILL_ENGINEERING))
1784 AddPct(damage, 25);
1785 break;
1786 }
1787 case 71132: // Glyph of Shadow Word: Pain
1788 damage = int32(CalculatePct(unitTarget->GetCreateMana(), 1)); // set 1 as value, missing in dbc
1789 break;
1790 default:
1791 break;
1792 }
1793
1794 if (level_diff > 0)
1795 damage -= level_multiplier * level_diff;
1796
1797 if (damage < 0)
1798 return;
1799
1800 m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power);
1801
1802 // Mad Alchemist's Potion
1803 if (m_spellInfo->Id == 45051)
1804 {
1805 // find elixirs on target
1806 bool guardianFound = false;
1807 bool battleFound = false;
1808 Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
1809 for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
1810 {
1811 uint32 spell_id = itr->second->GetBase()->GetId();
1812 if (!guardianFound)
1813 if (sSpellMgr->IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_GUARDIAN))
1814 guardianFound = true;
1815 if (!battleFound)
1816 if (sSpellMgr->IsSpellMemberOfSpellGroup(spell_id, SPELL_GROUP_ELIXIR_BATTLE))
1817 battleFound = true;
1818 if (battleFound && guardianFound)
1819 break;
1820 }
1821
1822 // get all available elixirs by mask and spell level
1823 std::set<uint32> avalibleElixirs;
1824 if (!guardianFound)
1825 sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, avalibleElixirs);
1826 if (!battleFound)
1827 sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, avalibleElixirs);
1828 for (std::set<uint32>::iterator itr = avalibleElixirs.begin(); itr != avalibleElixirs.end();)
1829 {
1830 SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(*itr);
1831 if (spellInfo->SpellLevel < m_spellInfo->SpellLevel || spellInfo->SpellLevel > unitTarget->getLevel())
1832 avalibleElixirs.erase(itr++);
1833 else if (sSpellMgr->IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_SHATTRATH))
1834 avalibleElixirs.erase(itr++);
1835 else if (sSpellMgr->IsSpellMemberOfSpellGroup(*itr, SPELL_GROUP_ELIXIR_UNSTABLE))
1836 avalibleElixirs.erase(itr++);
1837 else
1838 ++itr;
1839 }
1840
1841 if (!avalibleElixirs.empty())
1842 {
1843 // cast random elixir on target
1844 m_caster->CastSpell(unitTarget, Trinity::Containers::SelectRandomContainerElement(avalibleElixirs), true, m_CastItem);
1845 }
1846 }
1847}
1848
1849void Spell::EffectEnergizePct(SpellEffIndex effIndex)
1850{
1851 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1852 return;
1853
1854 if (!unitTarget)
1855 return;
1856 if (!unitTarget->IsAlive())
1857 return;
1858
1859 if (m_spellInfo->Effects[effIndex].MiscValue < 0 || m_spellInfo->Effects[effIndex].MiscValue >= int8(MAX_POWERS))
1860 return;
1861
1862 Powers power = Powers(m_spellInfo->Effects[effIndex].MiscValue);
1863
1864 if (unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->getPowerType() != power && !m_spellInfo->HasAttribute(SPELL_ATTR7_CAN_RESTORE_SECONDARY_POWER))
1865 return;
1866
1867 uint32 maxPower = unitTarget->GetMaxPower(power);
1868 if (maxPower == 0)
1869 return;
1870
1871 uint32 gain = CalculatePct(maxPower, damage);
1872 m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power);
1873}
1874
1875void Spell::SendLoot(ObjectGuid guid, LootType loottype)
1876{
1877 Player* player = m_caster->ToPlayer();
1878 if (!player)
1879 return;
1880
1881 if (gameObjTarget)
1882 {
1883 // Players shouldn't be able to loot gameobjects that are currently despawned
1884 if (!gameObjTarget->isSpawned() && !player->IsGameMaster())
1885 {
1886 TC_LOG_ERROR("spells", "Possible hacking attempt: Player %s [guid: %u] tried to loot a gameobject [entry: %u id: %u] which is on respawn time without being in GM mode!",
1887 player->GetName().c_str(), player->GetGUIDLow(), gameObjTarget->GetEntry(), gameObjTarget->GetGUIDLow());
1888 return;
1889 }
1890 // special case, already has GossipHello inside so return and avoid calling twice
1891 if (gameObjTarget->GetGoType() == GAMEOBJECT_TYPE_GOOBER)
1892 {
1893 gameObjTarget->Use(m_caster);
1894 return;
1895 }
1896
1897 if (sScriptMgr->OnGossipHello(player, gameObjTarget))
1898 return;
1899
1900 if (gameObjTarget->AI()->GossipHello(player))
1901 return;
1902
1903 switch (gameObjTarget->GetGoType())
1904 {
1905 case GAMEOBJECT_TYPE_DOOR:
1906 case GAMEOBJECT_TYPE_BUTTON:
1907 gameObjTarget->UseDoorOrButton(0, false, player);
1908 return;
1909
1910 case GAMEOBJECT_TYPE_QUESTGIVER:
1911 player->PrepareGossipMenu(gameObjTarget, gameObjTarget->GetGOInfo()->questgiver.gossipID, true);
1912 player->SendPreparedGossip(gameObjTarget);
1913 return;
1914
1915 case GAMEOBJECT_TYPE_SPELL_FOCUS:
1916 // triggering linked GO
1917 if (uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
1918 gameObjTarget->TriggeringLinkedGameObject(trapEntry, m_caster);
1919 return;
1920
1921 case GAMEOBJECT_TYPE_CHEST:
1922 /// @todo possible must be moved to loot release (in different from linked triggering)
1923 if (gameObjTarget->GetGOInfo()->chest.eventId)
1924 {
1925 TC_LOG_DEBUG("spells", "Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId, gameObjTarget->GetDBTableGUIDLow());
1926 player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
1927 }
1928
1929 // triggering linked GO
1930 if (uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
1931 gameObjTarget->TriggeringLinkedGameObject(trapEntry, m_caster);
1932
1933 // Don't return, let loots been taken
1934 default:
1935 break;
1936 }
1937 }
1938
1939 // Send loot
1940 player->SendLoot(guid, loottype);
1941}
1942
1943void Spell::EffectOpenLock(SpellEffIndex effIndex)
1944{
1945 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
1946 return;
1947
1948 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1949 {
1950 TC_LOG_DEBUG("spells", "WORLD: Open Lock - No Player Caster!");
1951 return;
1952 }
1953
1954 Player* player = m_caster->ToPlayer();
1955
1956 uint32 lockId = 0;
1957 ObjectGuid guid;
1958
1959 // Get lockId
1960 if (gameObjTarget)
1961 {
1962 GameObjectTemplate const* goInfo = gameObjTarget->GetGOInfo();
1963 // Arathi Basin banner opening. /// @todo Verify correctness of this check
1964 if ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) ||
1965 (goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK))
1966 {
1967 //CanUseBattlegroundObject() already called in CheckCast()
1968 // in battleground check
1969 if (Battleground* bg = player->GetBattleground())
1970 {
1971 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
1972 return;
1973 }
1974 }
1975 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
1976 {
1977 //CanUseBattlegroundObject() already called in CheckCast()
1978 // in battleground check
1979 if (Battleground* bg = player->GetBattleground())
1980 {
1981 if (bg->GetTypeID(true) == BATTLEGROUND_EY)
1982 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
1983 return;
1984 }
1985 }
1986 else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner())
1987 {
1988 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
1989 return;
1990 }
1991 /// @todo Add script for spell 41920 - Filling, becouse server it freze when use this spell
1992 // handle outdoor pvp object opening, return true if go was registered for handling
1993 // these objects must have been spawned by outdoorpvp!
1994 else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr->HandleOpenGo(player, gameObjTarget->GetGUID()))
1995 return;
1996 lockId = goInfo->GetLockId();
1997 guid = gameObjTarget->GetGUID();
1998 }
1999 else if (itemTarget)
2000 {
2001 lockId = itemTarget->GetTemplate()->LockID;
2002 guid = itemTarget->GetGUID();
2003 }
2004 else
2005 {
2006 TC_LOG_DEBUG("spells", "WORLD: Open Lock - No GameObject/Item Target!");
2007 return;
2008 }
2009
2010 SkillType skillId = SKILL_NONE;
2011 int32 reqSkillValue = 0;
2012 int32 skillValue;
2013
2014 SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue);
2015 if (res != SPELL_CAST_OK)
2016 {
2017 SendCastResult(res);
2018 return;
2019 }
2020
2021 if (gameObjTarget)
2022 SendLoot(guid, LOOT_SKINNING);
2023 else if (itemTarget)
2024 itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED);
2025
2026 // not allow use skill grow at item base open
2027 if (!m_CastItem && skillId != SKILL_NONE)
2028 {
2029 // update skill if really known
2030 if (uint32 pureSkillValue = player->GetPureSkillValue(skillId))
2031 {
2032 if (gameObjTarget)
2033 {
2034 // Allow one skill-up until respawned
2035 if (!gameObjTarget->IsInSkillupList(player->GetGUIDLow()) &&
2036 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue))
2037 gameObjTarget->AddToSkillupList(player->GetGUIDLow());
2038 }
2039 else if (itemTarget)
2040 {
2041 // Do one skill-up
2042 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
2043 }
2044 }
2045 }
2046 ExecuteLogEffectOpenLock(effIndex, gameObjTarget ? (Object*)gameObjTarget : (Object*)itemTarget);
2047}
2048
2049void Spell::EffectSummonChangeItem(SpellEffIndex effIndex)
2050{
2051 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2052 return;
2053
2054 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2055 return;
2056
2057 Player* player = m_caster->ToPlayer();
2058
2059 // applied only to using item
2060 if (!m_CastItem)
2061 return;
2062
2063 // ... only to item in own inventory/bank/equip_slot
2064 if (m_CastItem->GetOwnerGUID() != player->GetGUID())
2065 return;
2066
2067 uint32 newitemid = m_spellInfo->Effects[effIndex].ItemType;
2068 if (!newitemid)
2069 return;
2070
2071 uint16 pos = m_CastItem->GetPos();
2072
2073 Item* pNewItem = Item::CreateItem(newitemid, 1, player);
2074 if (!pNewItem)
2075 return;
2076
2077 for (uint8 j = PERM_ENCHANTMENT_SLOT; j <= TEMP_ENCHANTMENT_SLOT; ++j)
2078 if (m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
2079 pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
2080
2081 if (m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
2082 {
2083 double lossPercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
2084 player->DurabilityLoss(pNewItem, lossPercent);
2085 }
2086
2087 if (player->IsInventoryPos(pos))
2088 {
2089 ItemPosCountVec dest;
2090 InventoryResult msg = player->CanStoreItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true);
2091 if (msg == EQUIP_ERR_OK)
2092 {
2093 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
2094
2095 // prevent crash at access and unexpected charges counting with item update queue corrupt
2096 if (m_CastItem == m_targets.GetItemTarget())
2097 m_targets.SetItemTarget(NULL);
2098
2099 m_CastItem = NULL;
2100 m_castItemGUID.Clear();
2101 m_castItemEntry = 0;
2102
2103 player->StoreItem(dest, pNewItem, true);
2104 return;
2105 }
2106 }
2107 else if (player->IsBankPos(pos))
2108 {
2109 ItemPosCountVec dest;
2110 uint8 msg = player->CanBankItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true);
2111 if (msg == EQUIP_ERR_OK)
2112 {
2113 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
2114
2115 // prevent crash at access and unexpected charges counting with item update queue corrupt
2116 if (m_CastItem == m_targets.GetItemTarget())
2117 m_targets.SetItemTarget(NULL);
2118
2119 m_CastItem = NULL;
2120 m_castItemGUID.Clear();
2121 m_castItemEntry = 0;
2122
2123 player->BankItem(dest, pNewItem, true);
2124 return;
2125 }
2126 }
2127 else if (player->IsEquipmentPos(pos))
2128 {
2129 uint16 dest;
2130
2131 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true);
2132
2133 uint8 msg = player->CanEquipItem(m_CastItem->GetSlot(), dest, pNewItem, true);
2134
2135 if (msg == EQUIP_ERR_OK || msg == EQUIP_ERR_CANT_DO_RIGHT_NOW)
2136 {
2137 if (msg == EQUIP_ERR_CANT_DO_RIGHT_NOW) dest = EQUIPMENT_SLOT_MAINHAND;
2138
2139 // prevent crash at access and unexpected charges counting with item update queue corrupt
2140 if (m_CastItem == m_targets.GetItemTarget())
2141 m_targets.SetItemTarget(NULL);
2142
2143 m_CastItem = NULL;
2144 m_castItemGUID.Clear();
2145 m_castItemEntry = 0;
2146
2147 player->EquipItem(dest, pNewItem, true);
2148 player->AutoUnequipOffhandIfNeed();
2149 return;
2150 }
2151 }
2152
2153 // fail
2154 delete pNewItem;
2155}
2156
2157void Spell::EffectProficiency(SpellEffIndex /*effIndex*/)
2158{
2159 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2160 return;
2161
2162 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2163 return;
2164 Player* p_target = m_caster->ToPlayer();
2165
2166 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
2167 if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && !(p_target->GetWeaponProficiency() & subClassMask))
2168 {
2169 p_target->AddWeaponProficiency(subClassMask);
2170 p_target->SendProficiency(ITEM_CLASS_WEAPON, p_target->GetWeaponProficiency());
2171 }
2172 if (m_spellInfo->EquippedItemClass == ITEM_CLASS_ARMOR && !(p_target->GetArmorProficiency() & subClassMask))
2173 {
2174 p_target->AddArmorProficiency(subClassMask);
2175 p_target->SendProficiency(ITEM_CLASS_ARMOR, p_target->GetArmorProficiency());
2176 }
2177}
2178
2179void Spell::EffectSummonType(SpellEffIndex effIndex)
2180{
2181 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2182 return;
2183
2184 uint32 entry = m_spellInfo->Effects[effIndex].MiscValue;
2185 if (!entry)
2186 return;
2187
2188 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->Effects[effIndex].MiscValueB);
2189 if (!properties)
2190 {
2191 TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u", m_spellInfo->Effects[effIndex].MiscValueB);
2192 return;
2193 }
2194
2195 if (!m_originalCaster)
2196 return;
2197
2198 int32 duration = m_spellInfo->GetDuration();
2199 if (Player* modOwner = m_originalCaster->GetSpellModOwner())
2200 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
2201
2202 TempSummon* summon = NULL;
2203
2204 // determine how many units should be summoned
2205 uint32 numSummons;
2206
2207 // some spells need to summon many units, for those spells number of summons is stored in effect value
2208 // however so far noone found a generic check to find all of those (there's no related data in summonproperties.dbc
2209 // and in spell attributes, possibly we need to add a table for those)
2210 // so here's a list of MiscValueB values, which is currently most generic check
2211 switch (properties->Id)
2212 {
2213 case 64:
2214 case 61:
2215 case 1101:
2216 case 66:
2217 case 648:
2218 case 2301:
2219 case 1061:
2220 case 1261:
2221 case 629:
2222 case 181:
2223 case 715:
2224 case 1562:
2225 case 833:
2226 case 1161:
2227 case 713:
2228 numSummons = (damage > 0) ? damage : 1;
2229 break;
2230 default:
2231 numSummons = 1;
2232 break;
2233 }
2234
2235 switch (properties->Category)
2236 {
2237 case SUMMON_CATEGORY_WILD:
2238 case SUMMON_CATEGORY_ALLY:
2239 case SUMMON_CATEGORY_UNK:
2240 if (properties->Flags & 512)
2241 {
2242 SummonGuardian(effIndex, entry, properties, numSummons);
2243 break;
2244 }
2245 switch (properties->Type)
2246 {
2247 case SUMMON_TYPE_PET:
2248 case SUMMON_TYPE_GUARDIAN:
2249 case SUMMON_TYPE_GUARDIAN2:
2250 case SUMMON_TYPE_MINION:
2251 SummonGuardian(effIndex, entry, properties, numSummons);
2252 break;
2253 // Summons a vehicle, but doesn't force anyone to enter it (see SUMMON_CATEGORY_VEHICLE)
2254 case SUMMON_TYPE_VEHICLE:
2255 case SUMMON_TYPE_VEHICLE2:
2256 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2257 break;
2258 case SUMMON_TYPE_LIGHTWELL:
2259 case SUMMON_TYPE_TOTEM:
2260 {
2261 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2262 if (!summon || !summon->IsTotem())
2263 return;
2264
2265 // Mana Tide Totem
2266 if (m_spellInfo->Id == 16190)
2267 damage = m_caster->CountPctFromMaxHealth(10);
2268
2269 if (damage) // if not spell info, DB values used
2270 {
2271 summon->SetMaxHealth(damage);
2272 summon->SetHealth(damage);
2273 }
2274 break;
2275 }
2276 case SUMMON_TYPE_MINIPET:
2277 {
2278 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2279 if (!summon || !summon->HasUnitTypeMask(UNIT_MASK_MINION))
2280 return;
2281
2282 summon->SelectLevel(); // some summoned creaters have different from 1 DB data for level/hp
2283 summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureTemplate()->npcflag);
2284
2285 summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
2286
2287 summon->AI()->EnterEvadeMode();
2288 break;
2289 }
2290 default:
2291 {
2292 float radius = m_spellInfo->Effects[effIndex].CalcRadius();
2293
2294 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
2295
2296 for (uint32 count = 0; count < numSummons; ++count)
2297 {
2298 Position pos;
2299 if (count == 0)
2300 pos = *destTarget;
2301 else
2302 // randomize position for multiple summons
2303 pos = m_caster->GetRandomPoint(*destTarget, radius);
2304
2305 summon = m_originalCaster->SummonCreature(entry, pos, summonType, duration);
2306 if (!summon)
2307 continue;
2308
2309 if (properties->Category == SUMMON_CATEGORY_ALLY)
2310 {
2311 summon->SetOwnerGUID(m_originalCaster->GetGUID());
2312 summon->setFaction(m_originalCaster->getFaction());
2313 summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
2314 }
2315
2316 ExecuteLogEffectSummonObject(effIndex, summon);
2317 }
2318 return;
2319 }
2320 }//switch
2321 break;
2322 case SUMMON_CATEGORY_PET:
2323 SummonGuardian(effIndex, entry, properties, numSummons);
2324 break;
2325 case SUMMON_CATEGORY_PUPPET:
2326 summon = m_caster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_originalCaster, m_spellInfo->Id);
2327 break;
2328 case SUMMON_CATEGORY_VEHICLE:
2329 // Summoning spells (usually triggered by npc_spellclick) that spawn a vehicle and that cause the clicker
2330 // to cast a ride vehicle spell on the summoned unit.
2331 summon = m_originalCaster->GetMap()->SummonCreature(entry, *destTarget, properties, duration, m_caster, m_spellInfo->Id);
2332 if (!summon || !summon->IsVehicle())
2333 return;
2334
2335 // The spell that this effect will trigger. It has SPELL_AURA_CONTROL_VEHICLE
2336 uint32 spellId = VEHICLE_SPELL_RIDE_HARDCODED;
2337 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].CalcValue());
2338 if (spellInfo && spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
2339 spellId = spellInfo->Id;
2340
2341 // Hard coded enter vehicle spell
2342 m_originalCaster->CastSpell(summon, spellId, true);
2343
2344 uint32 faction = properties->Faction;
2345 if (!faction)
2346 faction = m_originalCaster->getFaction();
2347
2348 summon->setFaction(faction);
2349 break;
2350 }
2351
2352 if (summon)
2353 {
2354 summon->SetCreatorGUID(m_originalCaster->GetGUID());
2355 ExecuteLogEffectSummonObject(effIndex, summon);
2356 }
2357}
2358
2359void Spell::EffectLearnSpell(SpellEffIndex effIndex)
2360{
2361 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2362 return;
2363
2364 if (!unitTarget)
2365 return;
2366
2367 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2368 {
2369 if (unitTarget->ToPet())
2370 EffectLearnPetSpell(effIndex);
2371 return;
2372 }
2373
2374 Player* player = unitTarget->ToPlayer();
2375
2376 uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->Effects[effIndex].TriggerSpell;
2377 player->LearnSpell(spellToLearn, false);
2378
2379 TC_LOG_DEBUG("spells", "Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow());
2380}
2381
2382void Spell::EffectDispel(SpellEffIndex effIndex)
2383{
2384 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2385 return;
2386
2387 if (!unitTarget)
2388 return;
2389
2390 // Create dispel mask by dispel type
2391 uint32 dispel_type = m_spellInfo->Effects[effIndex].MiscValue;
2392 uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(dispel_type));
2393
2394 DispelChargesList dispel_list;
2395 unitTarget->GetDispellableAuraList(m_caster, dispelMask, dispel_list);
2396 if (dispel_list.empty())
2397 return;
2398
2399 // Ok if exist some buffs for dispel try dispel it
2400 uint32 failCount = 0;
2401 DispelChargesList success_list;
2402 WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
2403 // dispel N = damage buffs (or while exist buffs for dispel)
2404 for (int32 count = 0; count < damage && !dispel_list.empty();)
2405 {
2406 // Random select buff for dispel
2407 DispelChargesList::iterator itr = dispel_list.begin();
2408 std::advance(itr, urand(0, dispel_list.size() - 1));
2409
2410 int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
2411 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
2412 if (!chance)
2413 {
2414 dispel_list.erase(itr);
2415 continue;
2416 }
2417 else
2418 {
2419 if (roll_chance_i(chance))
2420 {
2421 bool alreadyListed = false;
2422 for (DispelChargesList::iterator successItr = success_list.begin(); successItr != success_list.end(); ++successItr)
2423 {
2424 if (successItr->first->GetId() == itr->first->GetId())
2425 {
2426 ++successItr->second;
2427 alreadyListed = true;
2428 }
2429 }
2430 if (!alreadyListed)
2431 success_list.push_back(std::make_pair(itr->first, 1));
2432 --itr->second;
2433 if (itr->second <= 0)
2434 dispel_list.erase(itr);
2435 }
2436 else
2437 {
2438 if (!failCount)
2439 {
2440 // Failed to dispell
2441 dataFail << uint64(m_caster->GetGUID()); // Caster GUID
2442 dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
2443 dataFail << uint32(m_spellInfo->Id); // dispel spell id
2444 }
2445 ++failCount;
2446 dataFail << uint32(itr->first->GetId()); // Spell Id
2447 }
2448 ++count;
2449 }
2450 }
2451
2452 if (failCount)
2453 m_caster->SendMessageToSet(&dataFail, true);
2454
2455 if (success_list.empty())
2456 return;
2457
2458 WorldPacket dataSuccess(SMSG_SPELLDISPELLOG, 8+8+4+1+4+success_list.size()*5);
2459 // Send packet header
2460 dataSuccess << unitTarget->GetPackGUID(); // Victim GUID
2461 dataSuccess << m_caster->GetPackGUID(); // Caster GUID
2462 dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
2463 dataSuccess << uint8(0); // not used
2464 dataSuccess << uint32(success_list.size()); // count
2465 for (DispelChargesList::iterator itr = success_list.begin(); itr != success_list.end(); ++itr)
2466 {
2467 // Send dispelled spell info
2468 dataSuccess << uint32(itr->first->GetId()); // Spell Id
2469 dataSuccess << uint8(0); // 0 - dispelled !=0 cleansed
2470 unitTarget->RemoveAurasDueToSpellByDispel(itr->first->GetId(), m_spellInfo->Id, itr->first->GetCasterGUID(), m_caster, itr->second);
2471 }
2472 m_caster->SendMessageToSet(&dataSuccess, true);
2473
2474 // On success dispel
2475 // Devour Magic
2476 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->GetCategory() == SPELLCATEGORY_DEVOUR_MAGIC)
2477 {
2478 int32 heal_amount = m_spellInfo->Effects[EFFECT_1].CalcValue();
2479 m_caster->CastCustomSpell(m_caster, 19658, &heal_amount, NULL, NULL, true);
2480 // Glyph of Felhunter
2481 if (Unit* owner = m_caster->GetOwner())
2482 if (owner->GetAura(56249))
2483 owner->CastCustomSpell(owner, 19658, &heal_amount, NULL, NULL, true);
2484 }
2485}
2486
2487void Spell::EffectDualWield(SpellEffIndex /*effIndex*/)
2488{
2489 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2490 return;
2491
2492 unitTarget->SetCanDualWield(true);
2493}
2494
2495void Spell::EffectPull(SpellEffIndex effIndex)
2496{
2497 /// @todo create a proper pull towards distract spell center for distract
2498 EffectNULL(effIndex);
2499}
2500
2501void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
2502{
2503 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2504 return;
2505
2506 // Check for possible target
2507 if (!unitTarget || unitTarget->IsInCombat())
2508 return;
2509
2510 // target must be OK to do this
2511 if (unitTarget->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING))
2512 return;
2513
2514 unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
2515 unitTarget->ClearUnitState(UNIT_STATE_MOVING);
2516
2517 if (unitTarget->GetTypeId() == TYPEID_UNIT)
2518 unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
2519}
2520
2521void Spell::EffectPickPocket(SpellEffIndex /*effIndex*/)
2522{
2523 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2524 return;
2525
2526 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2527 return;
2528
2529 // victim must be creature and attackable
2530 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget))
2531 return;
2532
2533 // victim have to be alive and humanoid or undead
2534 if (unitTarget->IsAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
2535 m_caster->ToPlayer()->SendLoot(unitTarget->GetGUID(), LOOT_PICKPOCKETING);
2536}
2537
2538void Spell::EffectAddFarsight(SpellEffIndex effIndex)
2539{
2540 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2541 return;
2542
2543 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2544 return;
2545
2546 float radius = m_spellInfo->Effects[effIndex].CalcRadius();
2547 int32 duration = m_spellInfo->GetDuration();
2548 // Caster not in world, might be spell triggered from aura removal
2549 if (!m_caster->IsInWorld())
2550 return;
2551
2552 DynamicObject* dynObj = new DynamicObject(true);
2553 if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS))
2554 {
2555 delete dynObj;
2556 return;
2557 }
2558
2559 dynObj->SetDuration(duration);
2560 dynObj->SetCasterViewpoint();
2561}
2562
2563void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)
2564{
2565 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2566 return;
2567
2568 if (!unitTarget || m_caster->GetTypeId() == TYPEID_PLAYER)
2569 return;
2570
2571 if (ObjectGuid guid = m_caster->GetGUID()) // the trainer is the caster
2572 unitTarget->ToPlayer()->SendTalentWipeConfirm(guid);
2573}
2574
2575void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex effIndex)
2576{
2577 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2578 return;
2579
2580 if (!unitTarget)
2581 return;
2582
2583 if (unitTarget->IsInFlight())
2584 return;
2585
2586 float dis = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
2587
2588 float fx, fy, fz;
2589 m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis);
2590
2591 unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
2592}
2593
2594void Spell::EffectLearnSkill(SpellEffIndex effIndex)
2595{
2596 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2597 return;
2598
2599 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2600 return;
2601
2602 if (damage < 0)
2603 return;
2604
2605 uint32 skillid = m_spellInfo->Effects[effIndex].MiscValue;
2606 SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(skillid, unitTarget->getRace(), unitTarget->getClass());
2607 if (!rcEntry)
2608 return;
2609
2610 SkillTiersEntry const* tier = sSkillTiersStore.LookupEntry(rcEntry->SkillTier);
2611 if (!tier)
2612 return;
2613
2614 uint16 skillval = unitTarget->ToPlayer()->GetPureSkillValue(skillid);
2615 unitTarget->ToPlayer()->SetSkill(skillid, m_spellInfo->Effects[effIndex].CalcValue(), std::max<uint16>(skillval, 1), tier->MaxSkill[damage - 1]);
2616}
2617
2618void Spell::EffectAddHonor(SpellEffIndex /*effIndex*/)
2619{
2620 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2621 return;
2622
2623 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2624 return;
2625
2626 // not scale value for item based reward (/10 value expected)
2627 if (m_CastItem)
2628 {
2629 unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage/10);
2630 TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(), unitTarget->ToPlayer()->GetGUIDLow());
2631 return;
2632 }
2633
2634 // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
2635 if (damage <= 50)
2636 {
2637 uint32 honor_reward = Trinity::Honor::hk_honor_at_level(unitTarget->getLevel(), float(damage));
2638 unitTarget->ToPlayer()->RewardHonor(NULL, 1, honor_reward);
2639 TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, unitTarget->ToPlayer()->GetGUIDLow());
2640 }
2641 else
2642 {
2643 //maybe we have correct honor_gain in damage already
2644 unitTarget->ToPlayer()->RewardHonor(NULL, 1, damage);
2645 TC_LOG_DEBUG("spells", "SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, unitTarget->ToPlayer()->GetGUIDLow());
2646 }
2647}
2648
2649void Spell::EffectTradeSkill(SpellEffIndex /*effIndex*/)
2650{
2651 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2652 return;
2653
2654 if (m_caster->GetTypeId() != TYPEID_PLAYER)
2655 return;
2656 // uint32 skillid = m_spellInfo->Effects[i].MiscValue;
2657 // uint16 skillmax = unitTarget->ToPlayer()->(skillid);
2658 // m_caster->ToPlayer()->SetSkill(skillid, skillval?skillval:1, skillmax+75);
2659}
2660
2661void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex)
2662{
2663 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2664 return;
2665
2666 if (!itemTarget)
2667 return;
2668
2669 Player* player = m_caster->ToPlayer();
2670 if (!player)
2671 return;
2672
2673 // Handle vellums
2674 if (itemTarget->IsWeaponVellum() || itemTarget->IsArmorVellum())
2675 {
2676 // destroy one vellum from stack
2677 uint32 count = 1;
2678 player->DestroyItemCount(itemTarget, count, true);
2679 unitTarget = player;
2680 // and add a scroll
2681 DoCreateItem(effIndex, m_spellInfo->Effects[effIndex].ItemType);
2682 itemTarget = NULL;
2683 m_targets.SetItemTarget(NULL);
2684 }
2685 else
2686 {
2687 // do not increase skill if vellum used
2688 if (!(m_CastItem && m_CastItem->GetTemplate()->Flags & ITEM_PROTO_FLAG_TRIGGERED_CAST))
2689 player->UpdateCraftSkill(m_spellInfo->Id);
2690
2691 uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue;
2692 if (!enchant_id)
2693 return;
2694
2695 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2696 if (!pEnchant)
2697 return;
2698
2699 // item can be in trade slot and have owner diff. from caster
2700 Player* item_owner = itemTarget->GetOwner();
2701 if (!item_owner)
2702 return;
2703
2704 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2705 {
2706 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2707 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2708 itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
2709 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2710 }
2711
2712 // remove old enchanting before applying new if equipped
2713 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, false);
2714
2715 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0, m_caster->GetGUID());
2716
2717 // add new enchanting if equipped
2718 item_owner->ApplyEnchantment(itemTarget, PERM_ENCHANTMENT_SLOT, true);
2719
2720 item_owner->RemoveTradeableItem(itemTarget);
2721 itemTarget->ClearSoulboundTradeable(item_owner);
2722 }
2723}
2724
2725void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex)
2726{
2727 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2728 return;
2729
2730 if (!itemTarget)
2731 return;
2732
2733 Player* player = m_caster->ToPlayer();
2734 if (!player)
2735 return;
2736
2737 uint32 enchantId = m_spellInfo->Effects[effIndex].MiscValue;
2738 if (!enchantId)
2739 return;
2740
2741 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2742 if (!enchant)
2743 return;
2744
2745 // support only enchantings with add socket in this slot
2746 {
2747 bool add_socket = false;
2748 for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
2749 {
2750 if (enchant->type[i] == ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
2751 {
2752 add_socket = true;
2753 break;
2754 }
2755 }
2756 if (!add_socket)
2757 {
2758 TC_LOG_ERROR("spells", "Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.",
2759 m_spellInfo->Id, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC, ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
2760 return;
2761 }
2762 }
2763
2764 // item can be in trade slot and have owner diff. from caster
2765 Player* item_owner = itemTarget->GetOwner();
2766 if (!item_owner)
2767 return;
2768
2769 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2770 {
2771 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
2772 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2773 itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
2774 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2775 }
2776
2777 // remove old enchanting before applying new if equipped
2778 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, false);
2779
2780 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchantId, 0, 0, m_caster->GetGUID());
2781
2782 // add new enchanting if equipped
2783 item_owner->ApplyEnchantment(itemTarget, PRISMATIC_ENCHANTMENT_SLOT, true);
2784
2785 item_owner->RemoveTradeableItem(itemTarget);
2786 itemTarget->ClearSoulboundTradeable(item_owner);
2787}
2788
2789void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex)
2790{
2791 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2792 return;
2793
2794 Player* player = m_caster->ToPlayer();
2795 if (!player)
2796 return;
2797
2798 // Rockbiter Weapon apply to both weapon
2799 if (!itemTarget)
2800 return;
2801 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000)
2802 {
2803 uint32 spell_id = 0;
2804
2805 // enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value
2806 // Note: damage calculated (correctly) with rounding int32(float(v)) but
2807 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
2808 switch (damage)
2809 {
2810 // Rank 1
2811 case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
2812 // Rank 2
2813 case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4]
2814 case 5: spell_id = 36751; break; // 20%
2815 // Rank 3
2816 case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6]
2817 case 7: spell_id = 36755; break; // 20%
2818 // Rank 4
2819 case 9: spell_id = 36761; break; // 0% [ 7% == 6]
2820 case 10: spell_id = 36758; break; // 14%
2821 case 11: spell_id = 36760; break; // 20%
2822 default:
2823 TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW", damage);
2824 return;
2825 }
2826
2827 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
2828 if (!spellInfo)
2829 {
2830 TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id);
2831 return;
2832
2833 }
2834
2835 for (int j = BASE_ATTACK; j <= OFF_ATTACK; ++j)
2836 {
2837 if (Item* item = player->GetWeaponForAttack(WeaponAttackType(j)))
2838 {
2839 if (item->IsFitToSpellRequirements(m_spellInfo))
2840 {
2841 Spell* spell = new Spell(m_caster, spellInfo, TRIGGERED_FULL_MASK);
2842 SpellCastTargets targets;
2843 targets.SetItemTarget(item);
2844 spell->prepare(&targets);
2845 }
2846 }
2847 }
2848 return;
2849 }
2850 if (!itemTarget)
2851 return;
2852
2853 uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue;
2854
2855 if (!enchant_id)
2856 {
2857 TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id", m_spellInfo->Id, effIndex);
2858 return;
2859 }
2860
2861 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
2862 if (!pEnchant)
2863 {
2864 TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ", m_spellInfo->Id, effIndex, enchant_id);
2865 return;
2866 }
2867
2868 // select enchantment duration
2869 uint32 duration;
2870
2871 // rogue family enchantments exception by duration
2872 if (m_spellInfo->Id == 38615)
2873 duration = 1800; // 30 mins
2874 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
2875 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE)
2876 duration = 3600; // 1 hour
2877 // shaman family enchantments
2878 else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN)
2879 duration = 1800; // 30 mins
2880 // other cases with this SpellVisual already selected
2881 else if (m_spellInfo->SpellVisual[0] == 215)
2882 duration = 1800; // 30 mins
2883 // some fishing pole bonuses except Glow Worm which lasts full hour
2884 else if (m_spellInfo->SpellVisual[0] == 563 && m_spellInfo->Id != 64401)
2885 duration = 600; // 10 mins
2886 // shaman rockbiter enchantments
2887 else if (m_spellInfo->SpellVisual[0] == 0)
2888 duration = 1800; // 30 mins
2889 else if (m_spellInfo->Id == 29702)
2890 duration = 300; // 5 mins
2891 else if (m_spellInfo->Id == 37360)
2892 duration = 300; // 5 mins
2893 // default case
2894 else
2895 duration = 3600; // 1 hour
2896
2897 // item can be in trade slot and have owner diff. from caster
2898 Player* item_owner = itemTarget->GetOwner();
2899 if (!item_owner)
2900 return;
2901
2902 if (item_owner != player && player->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
2903 {
2904 sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
2905 player->GetName().c_str(), player->GetSession()->GetAccountId(),
2906 itemTarget->GetTemplate()->Name1.c_str(), itemTarget->GetEntry(),
2907 item_owner->GetName().c_str(), item_owner->GetSession()->GetAccountId());
2908 }
2909
2910 // remove old enchanting before applying new if equipped
2911 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, false);
2912
2913 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration * 1000, 0, m_caster->GetGUID());
2914
2915 // add new enchanting if equipped
2916 item_owner->ApplyEnchantment(itemTarget, TEMP_ENCHANTMENT_SLOT, true);
2917}
2918
2919void Spell::EffectTameCreature(SpellEffIndex /*effIndex*/)
2920{
2921 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
2922 return;
2923
2924 if (m_caster->GetPetGUID())
2925 return;
2926
2927 if (!unitTarget)
2928 return;
2929
2930 if (unitTarget->GetTypeId() != TYPEID_UNIT)
2931 return;
2932
2933 Creature* creatureTarget = unitTarget->ToCreature();
2934
2935 if (creatureTarget->IsPet())
2936 return;
2937
2938 if (m_caster->getClass() != CLASS_HUNTER)
2939 return;
2940
2941 // cast finish successfully
2942 //SendChannelUpdate(0);
2943 finish();
2944
2945 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget, m_spellInfo->Id);
2946 if (!pet) // in very specific state like near world end/etc.
2947 return;
2948
2949 // "kill" original creature
2950 creatureTarget->DespawnOrUnsummon();
2951
2952 uint8 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
2953
2954 // prepare visual effect for levelup
2955 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
2956
2957 // add to world
2958 pet->GetMap()->AddToMap(pet->ToCreature());
2959
2960 // visual effect for levelup
2961 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
2962
2963 // caster have pet now
2964 m_caster->SetMinion(pet, true);
2965
2966 pet->InitTalentForLevel();
2967
2968 if (m_caster->GetTypeId() == TYPEID_PLAYER)
2969 {
2970 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
2971 m_caster->ToPlayer()->PetSpellInitialize();
2972 }
2973}
2974
2975void Spell::EffectSummonPet(SpellEffIndex effIndex)
2976{
2977 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
2978 return;
2979
2980 Player* owner = NULL;
2981 if (m_originalCaster)
2982 {
2983 owner = m_originalCaster->ToPlayer();
2984 if (!owner && m_originalCaster->IsTotem())
2985 owner = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
2986 }
2987
2988 uint32 petentry = m_spellInfo->Effects[effIndex].MiscValue;
2989
2990 if (!owner)
2991 {
2992 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(67);
2993 if (properties)
2994 SummonGuardian(effIndex, petentry, properties, 1);
2995 return;
2996 }
2997
2998 Pet* OldSummon = owner->GetPet();
2999
3000 // if pet requested type already exist
3001 if (OldSummon)
3002 {
3003 if (petentry == 0 || OldSummon->GetEntry() == petentry)
3004 {
3005 // pet in corpse state can't be summoned
3006 if (OldSummon->isDead())
3007 return;
3008
3009 ASSERT(OldSummon->GetMap() == owner->GetMap());
3010
3011 //OldSummon->GetMap()->Remove(OldSummon->ToCreature(), false);
3012
3013 float px, py, pz;
3014 owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3015
3016 OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation());
3017 //OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3018 //OldSummon->SetMap(owner->GetMap());
3019 //owner->GetMap()->Add(OldSummon->ToCreature());
3020
3021 if (owner->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled())
3022 owner->ToPlayer()->PetSpellInitialize();
3023
3024 return;
3025 }
3026
3027 if (owner->GetTypeId() == TYPEID_PLAYER)
3028 owner->ToPlayer()->RemovePet(OldSummon, (OldSummon->getPetType() == HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT), false);
3029 else
3030 return;
3031 }
3032
3033 float x, y, z;
3034 owner->GetClosePoint(x, y, z, owner->GetObjectSize());
3035 Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
3036 if (!pet)
3037 return;
3038
3039 if (m_caster->GetTypeId() == TYPEID_UNIT)
3040 {
3041 if (m_caster->IsTotem())
3042 pet->SetReactState(REACT_AGGRESSIVE);
3043 else
3044 pet->SetReactState(REACT_DEFENSIVE);
3045 }
3046
3047 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3048
3049 // generate new name for summon pet
3050 std::string new_name=sObjectMgr->GeneratePetName(petentry);
3051 if (!new_name.empty())
3052 pet->SetName(new_name);
3053
3054 ExecuteLogEffectSummonObject(effIndex, pet);
3055}
3056
3057void Spell::EffectLearnPetSpell(SpellEffIndex effIndex)
3058{
3059 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3060 return;
3061
3062 if (!unitTarget)
3063 return;
3064
3065 if (unitTarget->ToPlayer())
3066 {
3067 EffectLearnSpell(effIndex);
3068 return;
3069 }
3070 Pet* pet = unitTarget->ToPet();
3071 if (!pet)
3072 return;
3073
3074 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell);
3075 if (!learn_spellproto)
3076 return;
3077
3078 pet->learnSpell(learn_spellproto->Id);
3079 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3080 pet->GetOwner()->PetSpellInitialize();
3081}
3082
3083void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
3084{
3085 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3086 return;
3087
3088 if (!unitTarget)
3089 return;
3090
3091 // this effect use before aura Taunt apply for prevent taunt already attacking target
3092 // for spell as marked "non effective at already attacking target"
3093 if (!unitTarget || !unitTarget->CanHaveThreatList()
3094 || unitTarget->GetVictim() == m_caster)
3095 {
3096 SendCastResult(SPELL_FAILED_DONT_REPORT);
3097 return;
3098 }
3099
3100 if (m_spellInfo->Id == 62124)
3101 m_caster->CastSpell(unitTarget, 67485, true);
3102
3103 if (!unitTarget->getThreatManager().getOnlineContainer().empty())
3104 {
3105 // Also use this effect to set the taunter's threat to the taunted creature's highest value
3106 float myThreat = unitTarget->getThreatManager().getThreat(m_caster);
3107 float topThreat = unitTarget->getThreatManager().getOnlineContainer().getMostHated()->getThreat();
3108 if (topThreat > myThreat)
3109 unitTarget->getThreatManager().doAddThreat(m_caster, topThreat - myThreat);
3110
3111 //Set aggro victim to caster
3112 if (HostileReference* forcedVictim = unitTarget->getThreatManager().getOnlineContainer().getReferenceByTarget(m_caster))
3113 unitTarget->getThreatManager().setCurrentVictim(forcedVictim);
3114 }
3115
3116 if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE))
3117 unitTarget->ToCreature()->AI()->AttackStart(m_caster);
3118}
3119
3120void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
3121{
3122 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
3123 return;
3124
3125 if (!unitTarget || !unitTarget->IsAlive())
3126 return;
3127
3128 // multiple weapon dmg effect workaround
3129 // execute only the last weapon damage
3130 // and handle all effects at once
3131 for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j)
3132 {
3133 switch (m_spellInfo->Effects[j].Effect)
3134 {
3135 case SPELL_EFFECT_WEAPON_DAMAGE:
3136 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
3137 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
3138 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
3139 return; // we must calculate only at last weapon effect
3140 break;
3141 }
3142 }
3143
3144 // some spell specific modifiers
3145 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
3146 int32 fixed_bonus = 0;
3147 int32 spell_bonus = 0; // bonus specific for spell
3148
3149 switch (m_spellInfo->SpellFamilyName)
3150 {
3151 case SPELLFAMILY_WARRIOR:
3152 {
3153 // Devastate (player ones)
3154 if (m_spellInfo->SpellFamilyFlags[1] & 0x40)
3155 {
3156 // Player can apply only 58567 Sunder Armor effect.
3157 bool needCast = !unitTarget->HasAura(58567, m_caster->GetGUID());
3158 if (needCast)
3159 m_caster->CastSpell(unitTarget, 58567, true);
3160
3161 if (Aura* aur = unitTarget->GetAura(58567, m_caster->GetGUID()))
3162 {
3163 // 58388 - Glyph of Devastate dummy aura.
3164 if (int32 num = (needCast ? 0 : 1) + (m_caster->HasAura(58388) ? 1 : 0))
3165 aur->ModStackAmount(num);
3166 fixed_bonus += (aur->GetStackAmount() - 1) * CalculateDamage(2, unitTarget);
3167 }
3168 }
3169 if (m_spellInfo->SpellFamilyFlags[0] & 0x8000000) // Mocking Blow
3170 {
3171 if (unitTarget->IsImmunedToSpellEffect(m_spellInfo, EFFECT_1) || unitTarget->GetTypeId() == TYPEID_PLAYER)
3172 {
3173 m_damage = 0;
3174 return;
3175 }
3176 }
3177 break;
3178 }
3179 case SPELLFAMILY_ROGUE:
3180 {
3181 // Fan of Knives, Hemorrhage, Ghostly Strike
3182 if ((m_spellInfo->SpellFamilyFlags[1] & 0x40000)
3183 || (m_spellInfo->SpellFamilyFlags[0] & 0x6000000))
3184 {
3185 // Hemorrhage
3186 if (m_spellInfo->SpellFamilyFlags[0] & 0x2000000)
3187 {
3188 if (m_caster->GetTypeId() == TYPEID_PLAYER)
3189 m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this);
3190 }
3191 // 50% more damage with daggers
3192 if (m_caster->GetTypeId() == TYPEID_PLAYER)
3193 if (Item* item = m_caster->ToPlayer()->GetWeaponForAttack(m_attackType, true))
3194 if (item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
3195 totalDamagePercentMod *= 1.5f;
3196 }
3197 // Mutilate (for each hand)
3198 else if (m_spellInfo->SpellFamilyFlags[1] & 0x6)
3199 {
3200 bool found = false;
3201 // fast check
3202 if (unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON, m_spellInfo, m_caster))
3203 found = true;
3204 // full aura scan
3205 else
3206 {
3207 Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras();
3208 for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3209 {
3210 if (itr->second->GetBase()->GetSpellInfo()->Dispel == DISPEL_POISON)
3211 {
3212 found = true;
3213 break;
3214 }
3215 }
3216 }
3217
3218 if (found)
3219 totalDamagePercentMod *= 1.2f; // 120% if poisoned
3220 }
3221 break;
3222 }
3223 case SPELLFAMILY_PALADIN:
3224 {
3225 // Seal of Command Unleashed
3226 if (m_spellInfo->Id == 20467)
3227 {
3228 spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
3229 spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
3230 }
3231 break;
3232 }
3233 case SPELLFAMILY_SHAMAN:
3234 {
3235 // Skyshatter Harness item set bonus
3236 // Stormstrike
3237 if (AuraEffect* aurEff = m_caster->IsScriptOverriden(m_spellInfo, 5634))
3238 m_caster->CastSpell(m_caster, 38430, true, NULL, aurEff);
3239 break;
3240 }
3241 case SPELLFAMILY_DRUID:
3242 {
3243 // Mangle (Cat): CP
3244 if (m_spellInfo->SpellFamilyFlags[1] & 0x400)
3245 {
3246 if (m_caster->GetTypeId() == TYPEID_PLAYER)
3247 m_caster->ToPlayer()->AddComboPoints(unitTarget, 1, this);
3248 }
3249 // Shred, Maul - Rend and Tear
3250 else if (m_spellInfo->SpellFamilyFlags[0] & 0x00008800 && unitTarget->HasAuraState(AURA_STATE_BLEEDING))
3251 {
3252 if (AuraEffect const* rendAndTear = m_caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 0))
3253 AddPct(totalDamagePercentMod, rendAndTear->GetAmount());
3254 }
3255 break;
3256 }
3257 case SPELLFAMILY_HUNTER:
3258 {
3259 // Kill Shot - bonus damage from Ranged Attack Power
3260 if (m_spellInfo->SpellFamilyFlags[1] & 0x800000)
3261 spell_bonus += int32(0.4f * m_caster->GetTotalAttackPowerValue(RANGED_ATTACK));
3262 break;
3263 }
3264 case SPELLFAMILY_DEATHKNIGHT:
3265 {
3266 // Plague Strike
3267 if (m_spellInfo->SpellFamilyFlags[0] & 0x1)
3268 {
3269 // Glyph of Plague Strike
3270 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(58657, EFFECT_0))
3271 AddPct(totalDamagePercentMod, aurEff->GetAmount());
3272 break;
3273 }
3274 // Blood Strike
3275 if (m_spellInfo->SpellFamilyFlags[0] & 0x400000)
3276 {
3277 float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) / 2.0f;
3278 // Death Knight T8 Melee 4P Bonus
3279 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0))
3280 AddPct(bonusPct, aurEff->GetAmount());
3281 AddPct(totalDamagePercentMod, bonusPct);
3282
3283 // Glyph of Blood Strike
3284 if (m_caster->GetAuraEffect(59332, EFFECT_0))
3285 if (unitTarget->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED))
3286 AddPct(totalDamagePercentMod, 20);
3287 break;
3288 }
3289 // Death Strike
3290 if (m_spellInfo->SpellFamilyFlags[0] & 0x10)
3291 {
3292 // Glyph of Death Strike
3293 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(59336, EFFECT_0))
3294 if (uint32 runic = std::min<uint32>(m_caster->GetPower(POWER_RUNIC_POWER), aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue()))
3295 AddPct(totalDamagePercentMod, runic);
3296 break;
3297 }
3298 // Obliterate (12.5% more damage per disease)
3299 if (m_spellInfo->SpellFamilyFlags[1] & 0x20000)
3300 {
3301 bool consumeDiseases = true;
3302 // Annihilation
3303 if (AuraEffect const* aurEff = m_caster->GetDummyAuraEffect(SPELLFAMILY_DEATHKNIGHT, 2710, EFFECT_0))
3304 // Do not consume diseases if roll sucesses
3305 if (roll_chance_i(aurEff->GetAmount()))
3306 consumeDiseases = false;
3307
3308 float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID(), consumeDiseases) / 2.0f;
3309 // Death Knight T8 Melee 4P Bonus
3310 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0))
3311 AddPct(bonusPct, aurEff->GetAmount());
3312 AddPct(totalDamagePercentMod, bonusPct);
3313 break;
3314 }
3315 // Blood-Caked Strike - Blood-Caked Blade
3316 if (m_spellInfo->SpellIconID == 1736)
3317 {
3318 AddPct(totalDamagePercentMod, unitTarget->GetDiseasesByCaster(m_caster->GetGUID()) * 50.0f);
3319 break;
3320 }
3321 // Heart Strike
3322 if (m_spellInfo->SpellFamilyFlags[0] & 0x1000000)
3323 {
3324 float bonusPct = m_spellInfo->Effects[EFFECT_2].CalcValue() * unitTarget->GetDiseasesByCaster(m_caster->GetGUID());
3325 // Death Knight T8 Melee 4P Bonus
3326 if (AuraEffect const* aurEff = m_caster->GetAuraEffect(64736, EFFECT_0))
3327 AddPct(bonusPct, aurEff->GetAmount());
3328
3329 AddPct(totalDamagePercentMod, bonusPct);
3330 break;
3331 }
3332 break;
3333 }
3334 }
3335
3336 bool normalized = false;
3337 float weaponDamagePercentMod = 1.0f;
3338 for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
3339 {
3340 switch (m_spellInfo->Effects[j].Effect)
3341 {
3342 case SPELL_EFFECT_WEAPON_DAMAGE:
3343 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
3344 fixed_bonus += CalculateDamage(j, unitTarget);
3345 break;
3346 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
3347 fixed_bonus += CalculateDamage(j, unitTarget);
3348 normalized = true;
3349 break;
3350 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
3351 ApplyPct(weaponDamagePercentMod, CalculateDamage(j, unitTarget));
3352 break;
3353 default:
3354 break; // not weapon damage effect, just skip
3355 }
3356 }
3357
3358 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
3359 if (fixed_bonus || spell_bonus)
3360 {
3361 UnitMods unitMod;
3362 switch (m_attackType)
3363 {
3364 default:
3365 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
3366 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
3367 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
3368 }
3369
3370 float weapon_total_pct = 1.0f;
3371 if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL)
3372 weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
3373
3374 if (fixed_bonus)
3375 fixed_bonus = int32(fixed_bonus * weapon_total_pct);
3376 if (spell_bonus)
3377 spell_bonus = int32(spell_bonus * weapon_total_pct);
3378 }
3379
3380 int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true);
3381
3382 // Sequence is important
3383 for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
3384 {
3385 // We assume that a spell have at most one fixed_bonus
3386 // and at most one weaponDamagePercentMod
3387 switch (m_spellInfo->Effects[j].Effect)
3388 {
3389 case SPELL_EFFECT_WEAPON_DAMAGE:
3390 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
3391 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
3392 weaponDamage += fixed_bonus;
3393 break;
3394 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
3395 weaponDamage = int32(weaponDamage* weaponDamagePercentMod);
3396 default:
3397 break; // not weapon damage effect, just skip
3398 }
3399 }
3400
3401 if (spell_bonus)
3402 weaponDamage += spell_bonus;
3403
3404 if (totalDamagePercentMod != 1.0f)
3405 weaponDamage = int32(weaponDamage* totalDamagePercentMod);
3406
3407 // prevent negative damage
3408 uint32 eff_damage(std::max(weaponDamage, 0));
3409
3410 // Add melee damage bonuses (also check for negative)
3411 uint32 damageBonusDone = m_caster->MeleeDamageBonusDone(unitTarget, eff_damage, m_attackType, m_spellInfo);
3412
3413 m_damage += unitTarget->MeleeDamageBonusTaken(m_caster, damageBonusDone, m_attackType, m_spellInfo);
3414}
3415
3416void Spell::EffectThreat(SpellEffIndex /*effIndex*/)
3417{
3418 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3419 return;
3420
3421 if (!unitTarget || !unitTarget->IsAlive() || !m_caster->IsAlive())
3422 return;
3423
3424 if (!unitTarget->CanHaveThreatList())
3425 return;
3426
3427 unitTarget->AddThreat(m_caster, float(damage));
3428}
3429
3430void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
3431{
3432 // alistar fix lay on hands healing for full when there's a 50% reduced healing debuff
3433 if (m_caster->getClass() == CLASS_PALADIN)
3434 {
3435 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3436 return;
3437
3438 if (!unitTarget || !unitTarget->IsAlive())
3439 return;
3440
3441 int32 addhealth = m_caster->GetMaxHealth();
3442
3443 // Healing percent modifiers
3444 float NegativeMod = 1.0f;
3445
3446 addhealth = m_caster->GetMaxHealth();
3447
3448 // If player has healing reduction debuff
3449 float minval = float(unitTarget->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT));
3450 if (minval)
3451 NegativeMod *= (100.0f + minval) / 100.0f;
3452
3453 addhealth *= NegativeMod;
3454 m_healing += addhealth;
3455
3456 return;
3457 }
3458
3459 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3460 return;
3461
3462 if (!unitTarget || !unitTarget->IsAlive())
3463 return;
3464
3465 int32 addhealth = 0;
3466
3467 // damage == 0 - heal for caster max health
3468 if (damage == 0)
3469 addhealth = m_caster->GetMaxHealth();
3470 else
3471 addhealth = unitTarget->GetMaxHealth() - unitTarget->GetHealth();
3472
3473 m_healing += addhealth;
3474}
3475
3476void Spell::EffectInterruptCast(SpellEffIndex effIndex)
3477{
3478 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3479 return;
3480
3481 if (!unitTarget || !unitTarget->IsAlive())
3482 return;
3483
3484 /// @todo not all spells that used this effect apply cooldown at school spells
3485 // also exist case: apply cooldown to interrupted cast only and to all spells
3486 // there is no CURRENT_AUTOREPEAT_SPELL spells that can be interrupted
3487 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_AUTOREPEAT_SPELL; ++i)
3488 {
3489 if (Spell* spell = unitTarget->GetCurrentSpell(CurrentSpellTypes(i)))
3490 {
3491 SpellInfo const* curSpellInfo = spell->m_spellInfo;
3492 // check if we can interrupt spell
3493 if ((spell->getState() == SPELL_STATE_CASTING
3494 || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f))
3495 && curSpellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE
3496 && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT)
3497 || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->ChannelInterruptFlags & CHANNEL_INTERRUPT_FLAG_INTERRUPT)))
3498 {
3499 if (m_originalCaster)
3500 {
3501 int32 duration = m_spellInfo->GetDuration();
3502 unitTarget->GetSpellHistory()->LockSpellSchool(curSpellInfo->GetSchoolMask(), unitTarget->ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1 << effIndex));
3503 }
3504 ExecuteLogEffectInterruptCast(effIndex, unitTarget, curSpellInfo->Id);
3505 unitTarget->InterruptSpell(CurrentSpellTypes(i), false);
3506 }
3507 }
3508 }
3509}
3510
3511void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
3512{
3513 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
3514 return;
3515
3516 uint32 gameobject_id = m_spellInfo->Effects[effIndex].MiscValue;
3517
3518 GameObject* pGameObj = new GameObject;
3519
3520 WorldObject* target = focusObject;
3521 if (!target)
3522 target = m_caster;
3523
3524 float x, y, z;
3525 if (m_targets.HasDst())
3526 destTarget->GetPosition(x, y, z);
3527 else
3528 m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
3529
3530 Map* map = target->GetMap();
3531
3532 if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
3533 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
3534 {
3535 delete pGameObj;
3536 return;
3537 }
3538
3539 int32 duration = m_spellInfo->GetDuration();
3540
3541 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
3542 pGameObj->SetSpellId(m_spellInfo->Id);
3543
3544 ExecuteLogEffectSummonObject(effIndex, pGameObj);
3545
3546 // Wild object not have owner and check clickable by players
3547 map->AddToMap(pGameObj);
3548
3549 if (pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP)
3550 if (Player* player = m_caster->ToPlayer())
3551 if (Battleground* bg = player->GetBattleground())
3552 bg->SetDroppedFlagGUID(pGameObj->GetGUID(), player->GetTeam() == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE);
3553
3554 if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
3555 {
3556 GameObject* linkedGO = new GameObject;
3557 if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
3558 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
3559 {
3560 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
3561 linkedGO->SetSpellId(m_spellInfo->Id);
3562
3563 ExecuteLogEffectSummonObject(effIndex, linkedGO);
3564
3565 // Wild object not have owner and check clickable by players
3566 map->AddToMap(linkedGO);
3567 }
3568 else
3569 {
3570 delete linkedGO;
3571 linkedGO = NULL;
3572 return;
3573 }
3574 }
3575}
3576
3577void Spell::EffectScriptEffect(SpellEffIndex effIndex)
3578{
3579 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
3580 return;
3581
3582 /// @todo we must implement hunter pet summon at login there (spell 6962)
3583
3584 switch (m_spellInfo->SpellFamilyName)
3585 {
3586 case SPELLFAMILY_GENERIC:
3587 {
3588 switch (m_spellInfo->Id)
3589 {
3590 // Glyph of Backstab
3591 case 63975:
3592 {
3593 // search our Rupture aura on target
3594 if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x00100000, 0, 0, m_caster->GetGUID()))
3595 {
3596 uint32 countMin = aurEff->GetBase()->GetMaxDuration();
3597 uint32 countMax = 12000; // this can be wrong, duration should be based on combo-points
3598 countMax += m_caster->HasAura(56801) ? 4000 : 0;
3599
3600 if (countMin < countMax)
3601 {
3602 aurEff->GetBase()->SetDuration(uint32(aurEff->GetBase()->GetDuration() + 3000));
3603 aurEff->GetBase()->SetMaxDuration(countMin + 2000);
3604 }
3605
3606 }
3607 return;
3608 }
3609 // Glyph of Scourge Strike
3610 case 69961:
3611 {
3612 Unit::AuraEffectList const &mPeriodic = unitTarget->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE);
3613 for (Unit::AuraEffectList::const_iterator i = mPeriodic.begin(); i != mPeriodic.end(); ++i)
3614 {
3615 AuraEffect const* aurEff = *i;
3616 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
3617 // search our Blood Plague and Frost Fever on target
3618 if (spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && spellInfo->SpellFamilyFlags[2] & 0x2 &&
3619 aurEff->GetCasterGUID() == m_caster->GetGUID())
3620 {
3621 uint32 countMin = aurEff->GetBase()->GetMaxDuration();
3622 uint32 countMax = spellInfo->GetMaxDuration();
3623
3624 // this Glyph
3625 countMax += 9000;
3626 // talent Epidemic
3627 if (AuraEffect const* epidemic = m_caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 234, EFFECT_0))
3628 countMax += epidemic->GetAmount();
3629
3630 if (countMin < countMax)
3631 {
3632 aurEff->GetBase()->SetDuration(aurEff->GetBase()->GetDuration() + 3000);
3633 aurEff->GetBase()->SetMaxDuration(countMin + 3000);
3634 }
3635 }
3636 }
3637 return;
3638 }
3639 case 55693: // Remove Collapsing Cave Aura
3640 if (!unitTarget)
3641 return;
3642 unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].CalcValue());
3643 break;
3644 // Bending Shinbone
3645 case 8856:
3646 {
3647 if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
3648 return;
3649
3650 uint32 spell_id = roll_chance_i(20) ? 8854 : 8855;
3651
3652 m_caster->CastSpell(m_caster, spell_id, true, NULL);
3653 return;
3654 }
3655 // Brittle Armor - need remove one 24575 Brittle Armor aura
3656 case 24590:
3657 unitTarget->RemoveAuraFromStack(24575);
3658 return;
3659 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
3660 case 26465:
3661 unitTarget->RemoveAuraFromStack(26464);
3662 return;
3663 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
3664 case 22539:
3665 case 22972:
3666 case 22975:
3667 case 22976:
3668 case 22977:
3669 case 22978:
3670 case 22979:
3671 case 22980:
3672 case 22981:
3673 case 22982:
3674 case 22983:
3675 case 22984:
3676 case 22985:
3677 {
3678 if (!unitTarget || !unitTarget->IsAlive())
3679 return;
3680
3681 // Onyxia Scale Cloak
3682 if (unitTarget->HasAura(22683))
3683 return;
3684
3685 // Shadow Flame
3686 m_caster->CastSpell(unitTarget, 22682, true);
3687 return;
3688 }
3689 // Decimate
3690 case 28374:
3691 case 54426:
3692 if (unitTarget)
3693 {
3694 int32 decimateDamage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5));
3695 if (decimateDamage > 0)
3696 m_caster->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, decimateDamage, unitTarget);
3697 }
3698 return;
3699 // Mirren's Drinking Hat
3700 case 29830:
3701 {
3702 uint32 item = 0;
3703 switch (urand(1, 6))
3704 {
3705 case 1:
3706 case 2:
3707 case 3:
3708 item = 23584; break; // Loch Modan Lager
3709 case 4:
3710 case 5:
3711 item = 23585; break; // Stouthammer Lite
3712 case 6:
3713 item = 23586; break; // Aerie Peak Pale Ale
3714 }
3715 if (item)
3716 DoCreateItem(effIndex, item);
3717 break;
3718 }
3719 case 20589: // Escape artist
3720 case 30918: // Improved Sprint
3721 {
3722 // Removes snares and roots.
3723 unitTarget->RemoveMovementImpairingAuras();
3724 break;
3725 }
3726 // Plant Warmaul Ogre Banner
3727 case 32307:
3728 if (Player* caster = m_caster->ToPlayer())
3729 {
3730 caster->RewardPlayerAndGroupAtEvent(18388, unitTarget);
3731 if (Creature* target = unitTarget->ToCreature())
3732 {
3733 target->setDeathState(CORPSE);
3734 target->RemoveCorpse();
3735 }
3736 }
3737 break;
3738 // Mug Transformation
3739 case 41931:
3740 {
3741 if (m_caster->GetTypeId() != TYPEID_PLAYER)
3742 return;
3743
3744 uint8 bag = 19;
3745 uint8 slot = 0;
3746 Item* item = NULL;
3747
3748 while (bag) // 256 = 0 due to var type
3749 {
3750 item = m_caster->ToPlayer()->GetItemByPos(bag, slot);
3751 if (item && item->GetEntry() == 38587)
3752 break;
3753
3754 ++slot;
3755 if (slot == 39)
3756 {
3757 slot = 0;
3758 ++bag;
3759 }
3760 }
3761 if (bag)
3762 {
3763 if (m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount() == 1) m_caster->ToPlayer()->RemoveItem(bag, slot, true);
3764 else m_caster->ToPlayer()->GetItemByPos(bag, slot)->SetCount(m_caster->ToPlayer()->GetItemByPos(bag, slot)->GetCount()-1);
3765 // Spell 42518 (Braufest - Gratisprobe des Braufest herstellen)
3766 m_caster->CastSpell(m_caster, 42518, true);
3767 return;
3768 }
3769 break;
3770 }
3771 // Brutallus - Burn
3772 case 45141:
3773 case 45151:
3774 {
3775 //Workaround for Range ... should be global for every ScriptEffect
3776 float radius = m_spellInfo->Effects[effIndex].CalcRadius();
3777 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER && unitTarget->GetDistance(m_caster) >= radius && !unitTarget->HasAura(46394) && unitTarget != m_caster)
3778 unitTarget->CastSpell(unitTarget, 46394, true);
3779
3780 break;
3781 }
3782 // Goblin Weather Machine
3783 case 46203:
3784 {
3785 if (!unitTarget)
3786 return;
3787
3788 uint32 spellId = 0;
3789 switch (rand32() % 4)
3790 {
3791 case 0: spellId = 46740; break;
3792 case 1: spellId = 46739; break;
3793 case 2: spellId = 46738; break;
3794 case 3: spellId = 46736; break;
3795 }
3796 unitTarget->CastSpell(unitTarget, spellId, true);
3797 break;
3798 }
3799 // 5, 000 Gold
3800 case 46642:
3801 {
3802 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3803 return;
3804
3805 unitTarget->ToPlayer()->ModifyMoney(5000 * GOLD);
3806
3807 break;
3808 }
3809 // Roll Dice - Decahedral Dwarven Dice
3810 case 47770:
3811 {
3812 char buf[128];
3813 const char *gender = "his";
3814 if (m_caster->getGender() > 0)
3815 gender = "her";
3816 sprintf(buf, "%s rubs %s [Decahedral Dwarven Dice] between %s hands and rolls. One %u and one %u.", m_caster->GetName().c_str(), gender, gender, urand(1, 10), urand(1, 10));
3817 m_caster->TextEmote(buf);
3818 break;
3819 }
3820 // Roll 'dem Bones - Worn Troll Dice
3821 case 47776:
3822 {
3823 char buf[128];
3824 const char *gender = "his";
3825 if (m_caster->getGender() > 0)
3826 gender = "her";
3827 sprintf(buf, "%s causually tosses %s [Worn Troll Dice]. One %u and one %u.", m_caster->GetName().c_str(), gender, urand(1, 6), urand(1, 6));
3828 m_caster->TextEmote(buf);
3829 break;
3830 }
3831 // Death Knight Initiate Visual
3832 case 51519:
3833 {
3834 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
3835 return;
3836
3837 uint32 iTmpSpellId = 0;
3838 switch (unitTarget->GetDisplayId())
3839 {
3840 case 25369: iTmpSpellId = 51552; break; // bloodelf female
3841 case 25373: iTmpSpellId = 51551; break; // bloodelf male
3842 case 25363: iTmpSpellId = 51542; break; // draenei female
3843 case 25357: iTmpSpellId = 51541; break; // draenei male
3844 case 25361: iTmpSpellId = 51537; break; // dwarf female
3845 case 25356: iTmpSpellId = 51538; break; // dwarf male
3846 case 25372: iTmpSpellId = 51550; break; // forsaken female
3847 case 25367: iTmpSpellId = 51549; break; // forsaken male
3848 case 25362: iTmpSpellId = 51540; break; // gnome female
3849 case 25359: iTmpSpellId = 51539; break; // gnome male
3850 case 25355: iTmpSpellId = 51534; break; // human female
3851 case 25354: iTmpSpellId = 51520; break; // human male
3852 case 25360: iTmpSpellId = 51536; break; // nightelf female
3853 case 25358: iTmpSpellId = 51535; break; // nightelf male
3854 case 25368: iTmpSpellId = 51544; break; // orc female
3855 case 25364: iTmpSpellId = 51543; break; // orc male
3856 case 25371: iTmpSpellId = 51548; break; // tauren female
3857 case 25366: iTmpSpellId = 51547; break; // tauren male
3858 case 25370: iTmpSpellId = 51545; break; // troll female
3859 case 25365: iTmpSpellId = 51546; break; // troll male
3860 default: return;
3861 }
3862
3863 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
3864 Creature* npc = unitTarget->ToCreature();
3865 npc->LoadEquipment();
3866 return;
3867 }
3868 // Deathbolt from Thalgran Blightbringer
3869 // reflected by Freya's Ward
3870 // Retribution by Sevenfold Retribution
3871 case 51854:
3872 {
3873 if (!unitTarget)
3874 return;
3875 if (unitTarget->HasAura(51845))
3876 unitTarget->CastSpell(m_caster, 51856, true);
3877 else
3878 m_caster->CastSpell(unitTarget, 51855, true);
3879 break;
3880 }
3881 // Summon Ghouls On Scarlet Crusade
3882 case 51904:
3883 {
3884 if (!m_targets.HasDst())
3885 return;
3886
3887 float x, y, z;
3888 float radius = m_spellInfo->Effects[effIndex].CalcRadius();
3889 for (uint8 i = 0; i < 15; ++i)
3890 {
3891 m_caster->GetRandomPoint(*destTarget, radius, x, y, z);
3892 m_caster->CastSpell(x, y, z, 54522, true);
3893 }
3894 break;
3895 }
3896 case 52173: // Coyote Spirit Despawn
3897 case 60243: // Blood Parrot Despawn
3898 if (unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsSummon())
3899 unitTarget->ToTempSummon()->UnSummon();
3900 return;
3901 case 52479: // Gift of the Harvester
3902 if (unitTarget && m_originalCaster)
3903 m_originalCaster->CastSpell(unitTarget, urand(0, 1) ? damage : 52505, true);
3904 return;
3905 case 53110: // Devour Humanoid
3906 if (unitTarget)
3907 unitTarget->CastSpell(m_caster, damage, true);
3908 return;
3909 case 57347: // Retrieving (Wintergrasp RP-GG pickup spell)
3910 {
3911 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->GetTypeId() != TYPEID_PLAYER)
3912 return;
3913
3914 unitTarget->ToCreature()->DespawnOrUnsummon();
3915
3916 return;
3917 }
3918 case 57349: // Drop RP-GG (Wintergrasp RP-GG at death drop spell)
3919 {
3920 if (m_caster->GetTypeId() != TYPEID_PLAYER)
3921 return;
3922
3923 // Delete item from inventory at death
3924 m_caster->ToPlayer()->DestroyItemCount(damage, 5, true);
3925
3926 return;
3927 }
3928 case 58418: // Portal to Orgrimmar
3929 case 58420: // Portal to Stormwind
3930 {
3931 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex != 0)
3932 return;
3933
3934 uint32 spellID = m_spellInfo->Effects[EFFECT_0].CalcValue();
3935 uint32 questID = m_spellInfo->Effects[EFFECT_1].CalcValue();
3936
3937 if (unitTarget->ToPlayer()->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE)
3938 unitTarget->CastSpell(unitTarget, spellID, true);
3939
3940 return;
3941 }
3942 case 58983: // Big Blizzard Bear
3943 {
3944 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3945 return;
3946
3947 // Prevent stacking of mounts and client crashes upon dismounting
3948 unitTarget->RemoveAurasByType(SPELL_AURA_MOUNTED);
3949
3950 // Triggered spell id dependent on riding skill
3951 if (uint16 skillval = unitTarget->ToPlayer()->GetSkillValue(SKILL_RIDING))
3952 {
3953 if (skillval >= 150)
3954 unitTarget->CastSpell(unitTarget, 58999, true);
3955 else
3956 unitTarget->CastSpell(unitTarget, 58997, true);
3957 }
3958 return;
3959 }
3960 case 59317: // Teleporting
3961 {
3962
3963 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3964 return;
3965
3966 // return from top
3967 if (unitTarget->ToPlayer()->GetAreaId() == 4637)
3968 unitTarget->CastSpell(unitTarget, 59316, true);
3969 // teleport atop
3970 else
3971 unitTarget->CastSpell(unitTarget, 59314, true);
3972
3973 return;
3974 }
3975 case 62482: // Grab Crate
3976 {
3977 if (unitTarget)
3978 {
3979 if (Unit* seat = m_caster->GetVehicleBase())
3980 {
3981 if (Unit* parent = seat->GetVehicleBase())
3982 {
3983 /// @todo a hack, range = 11, should after some time cast, otherwise too far
3984 m_caster->CastSpell(parent, 62496, true);
3985 unitTarget->CastSpell(parent, m_spellInfo->Effects[EFFECT_0].CalcValue());
3986 }
3987 }
3988 }
3989 return;
3990 }
3991 case 60123: // Lightwell
3992 {
3993 if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->IsSummon())
3994 return;
3995
3996 uint32 spell_heal;
3997
3998 switch (m_caster->GetEntry())
3999 {
4000 case 31897: spell_heal = 7001; break;
4001 case 31896: spell_heal = 27873; break;
4002 case 31895: spell_heal = 27874; break;
4003 case 31894: spell_heal = 28276; break;
4004 case 31893: spell_heal = 48084; break;
4005 case 31883: spell_heal = 48085; break;
4006 default:
4007 TC_LOG_ERROR("spells", "Unknown Lightwell spell caster %u", m_caster->GetEntry());
4008 return;
4009 }
4010
4011 // proc a spellcast
4012 if (Aura* chargesAura = m_caster->GetAura(59907))
4013 {
4014 m_caster->CastSpell(unitTarget, spell_heal, true, NULL, NULL, m_caster->ToTempSummon()->GetSummonerGUID());
4015 if (chargesAura->ModCharges(-1))
4016 m_caster->ToTempSummon()->UnSummon();
4017 }
4018
4019 return;
4020 }
4021 // Stoneclaw Totem
4022 case 55328: // Rank 1
4023 case 55329: // Rank 2
4024 case 55330: // Rank 3
4025 case 55332: // Rank 4
4026 case 55333: // Rank 5
4027 case 55335: // Rank 6
4028 case 55278: // Rank 7
4029 case 58589: // Rank 8
4030 case 58590: // Rank 9
4031 case 58591: // Rank 10
4032 {
4033 int32 basepoints0 = damage;
4034 // Cast Absorb on totems
4035 for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
4036 {
4037 if (!unitTarget->m_SummonSlot[slot])
4038 continue;
4039
4040 Creature* totem = unitTarget->GetMap()->GetCreature(unitTarget->m_SummonSlot[slot]);
4041 if (totem && totem->IsTotem())
4042 {
4043 m_caster->CastCustomSpell(totem, 55277, &basepoints0, NULL, NULL, true);
4044 }
4045 }
4046 // Glyph of Stoneclaw Totem
4047 if (AuraEffect* aur=unitTarget->GetAuraEffect(63298, 0))
4048 {
4049 basepoints0 *= aur->GetAmount();
4050 m_caster->CastCustomSpell(unitTarget, 55277, &basepoints0, NULL, NULL, true);
4051 }
4052 break;
4053 }
4054 case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster
4055 {
4056 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
4057 return;
4058
4059 if (roll_chance_i(50)) // chance unknown, using 50
4060 return;
4061
4062 static uint32 const spellPlayer[5] =
4063 {
4064 45674, // Bigger!
4065 45675, // Shrunk
4066 45678, // Yellow
4067 45682, // Ghost
4068 45684 // Polymorph
4069 };
4070
4071 static uint32 const spellTarget[5] =
4072 {
4073 45673, // Bigger!
4074 45672, // Shrunk
4075 45677, // Yellow
4076 45681, // Ghost
4077 45683 // Polymorph
4078 };
4079
4080 m_caster->CastSpell(m_caster, spellPlayer[urand(0, 4)], true);
4081 unitTarget->CastSpell(unitTarget, spellTarget[urand(0, 4)], true);
4082 break;
4083 }
4084 }
4085 break;
4086 }
4087 }
4088
4089 // normal DB scripted effect
4090 TC_LOG_DEBUG("spells", "Spell ScriptStart spellid %u in EffectScriptEffect(%u)", m_spellInfo->Id, effIndex);
4091 m_caster->GetMap()->ScriptsStart(sSpellScripts, uint32(m_spellInfo->Id | (effIndex << 24)), m_caster, unitTarget);
4092}
4093
4094void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/)
4095{
4096 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4097 return;
4098
4099 if (!unitTarget)
4100 return;
4101
4102 // alistar don't auto attack while under shadowmeld / invis
4103 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
4104 unitTarget->ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
4105
4106 unitTarget->getHostileRefManager().UpdateVisibility();
4107
4108 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
4109 for (Unit::AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
4110 {
4111 if (!(*itr)->CanSeeOrDetect(unitTarget))
4112 (*(itr++))->AttackStop();
4113 else
4114 ++itr;
4115 }
4116
4117 unitTarget->m_lastSanctuaryTime = getMSTime();
4118
4119 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4120 if (m_caster->GetTypeId() == TYPEID_PLAYER
4121 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
4122 && (m_spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VANISH))
4123 {
4124 m_caster->ToPlayer()->RemoveAurasByType(SPELL_AURA_MOD_ROOT);
4125 // Overkill
4126 if (m_caster->ToPlayer()->HasSpell(58426))
4127 m_caster->CastSpell(m_caster, 58427, true);
4128 }
4129}
4130
4131void Spell::EffectAddComboPoints(SpellEffIndex /*effIndex*/)
4132{
4133 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4134 return;
4135
4136 if (!unitTarget)
4137 return;
4138
4139 if (!m_caster->m_movedPlayer)
4140 return;
4141
4142 if (damage <= 0)
4143 return;
4144
4145 m_caster->m_movedPlayer->AddComboPoints(unitTarget, damage, this);
4146}
4147
4148void Spell::EffectDuel(SpellEffIndex effIndex)
4149{
4150 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4151 return;
4152
4153 if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4154 return;
4155
4156 Player* caster = m_caster->ToPlayer();
4157 Player* target = unitTarget->ToPlayer();
4158
4159 // caster or target already have requested duel
4160 if (caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()))
4161 return;
4162
4163 // Players can only fight a duel in zones with this flag
4164 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId());
4165 if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
4166 {
4167 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4168 return;
4169 }
4170
4171 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId());
4172 if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
4173 {
4174 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4175 return;
4176 }
4177
4178 //CREATE DUEL FLAG OBJECT
4179 GameObject* pGameObj = new GameObject;
4180
4181 uint32 gameobject_id = m_spellInfo->Effects[effIndex].MiscValue;
4182
4183 Map* map = m_caster->GetMap();
4184 if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
4185 map, m_caster->GetPhaseMask(),
4186 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2,
4187 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2,
4188 m_caster->GetPositionZ(),
4189 m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
4190 {
4191 delete pGameObj;
4192 return;
4193 }
4194
4195 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction());
4196 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1);
4197 int32 duration = m_spellInfo->GetDuration();
4198 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
4199 pGameObj->SetSpellId(m_spellInfo->Id);
4200
4201 ExecuteLogEffectSummonObject(effIndex, pGameObj);
4202
4203 m_caster->AddGameObject(pGameObj);
4204 map->AddToMap(pGameObj);
4205 //END
4206
4207 // Send request
4208 WorldPacket data(SMSG_DUEL_REQUESTED, 8 + 8);
4209 data << uint64(pGameObj->GetGUID());
4210 data << uint64(caster->GetGUID());
4211 caster->GetSession()->SendPacket(&data);
4212 target->GetSession()->SendPacket(&data);
4213
4214 // create duel-info
4215 DuelInfo* duel = new DuelInfo;
4216 duel->initiator = caster;
4217 duel->opponent = target;
4218 duel->startTime = 0;
4219 duel->startTimer = 0;
4220 duel->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel
4221 caster->duel = duel;
4222
4223 DuelInfo* duel2 = new DuelInfo;
4224 duel2->initiator = caster;
4225 duel2->opponent = caster;
4226 duel2->startTime = 0;
4227 duel2->startTimer = 0;
4228 duel2->isMounted = (GetSpellInfo()->Id == 62875); // Mounted Duel
4229 target->duel = duel2;
4230
4231 caster->SetGuidValue(PLAYER_DUEL_ARBITER, pGameObj->GetGUID());
4232 target->SetGuidValue(PLAYER_DUEL_ARBITER, pGameObj->GetGUID());
4233
4234 sScriptMgr->OnPlayerDuelRequest(target, caster);
4235}
4236
4237void Spell::EffectStuck(SpellEffIndex /*effIndex*/)
4238{
4239 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4240 return;
4241
4242 if (!sWorld->getBoolConfig(CONFIG_CAST_UNSTUCK))
4243 return;
4244
4245 Player* player = m_caster->ToPlayer();
4246 if (!player)
4247 return;
4248
4249 TC_LOG_DEBUG("spells", "Spell Effect: Stuck");
4250 TC_LOG_DEBUG("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
4251
4252 if (player->IsInFlight())
4253 return;
4254
4255 player->TeleportTo(player->GetStartPosition(), TELE_TO_SPELL);
4256 // homebind location is loaded always
4257 // target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->GetOrientation(), (m_caster == m_caster ? TELE_TO_SPELL : 0));
4258
4259 // Stuck spell trigger Hearthstone cooldown
4260 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(8690);
4261 if (!spellInfo)
4262 return;
4263 Spell spell(player, spellInfo, TRIGGERED_FULL_MASK);
4264 spell.SendSpellCooldown();
4265}
4266
4267void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/)
4268{
4269 // workaround - this effect should not use target map
4270 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4271 return;
4272
4273 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4274 return;
4275
4276 // Evil Twin (ignore player summon, but hide this for summoner)
4277 if (unitTarget->HasAura(23445))
4278 return;
4279
4280 float x, y, z;
4281 m_caster->GetPosition(x, y, z);
4282
4283 unitTarget->ToPlayer()->SetSummonPoint(m_caster->GetMapId(), x, y, z);
4284
4285 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
4286 data << uint64(m_caster->GetGUID()); // summoner guid
4287 data << uint32(m_caster->GetZoneId()); // summoner zone
4288 data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILLISECONDS); // auto decline after msecs
4289 unitTarget->ToPlayer()->GetSession()->SendPacket(&data);
4290}
4291
4292void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/)
4293{
4294 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4295 return;
4296
4297 if (!gameObjTarget)
4298 return;
4299
4300 ScriptInfo activateCommand;
4301 activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
4302
4303 // int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research
4304
4305 gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, m_caster, gameObjTarget);
4306}
4307
4308void Spell::EffectApplyGlyph(SpellEffIndex effIndex)
4309{
4310 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4311 return;
4312
4313 if (m_glyphIndex >= MAX_GLYPH_SLOT_INDEX)
4314 return;
4315
4316 Player* player = m_caster->ToPlayer();
4317 if (!player)
4318 return;
4319
4320 // glyph sockets level requirement
4321 uint8 minLevel = 0;
4322 switch (m_glyphIndex)
4323 {
4324 case 0:
4325 case 1: minLevel = 15; break;
4326 case 2: minLevel = 50; break;
4327 case 3: minLevel = 30; break;
4328 case 4: minLevel = 70; break;
4329 case 5: minLevel = 80; break;
4330 }
4331 if (minLevel && m_caster->getLevel() < minLevel)
4332 {
4333 SendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED);
4334 return;
4335 }
4336
4337 // apply new one
4338 if (uint32 glyph = m_spellInfo->Effects[effIndex].MiscValue)
4339 {
4340 if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph))
4341 {
4342 if (GlyphSlotEntry const* gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
4343 {
4344 if (gp->TypeFlags != gs->TypeFlags)
4345 {
4346 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
4347 return; // glyph slot mismatch
4348 }
4349 }
4350
4351 // remove old glyph
4352 if (uint32 oldglyph = player->GetGlyph(m_glyphIndex))
4353 {
4354 if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
4355 {
4356 player->RemoveAurasDueToSpell(old_gp->SpellId);
4357 player->SetGlyph(m_glyphIndex, 0);
4358 }
4359 }
4360
4361 player->CastSpell(m_caster, gp->SpellId, true);
4362 player->SetGlyph(m_glyphIndex, glyph);
4363 player->SendTalentsInfoData(false);
4364 }
4365 }
4366}
4367
4368void Spell::EffectEnchantHeldItem(SpellEffIndex effIndex)
4369{
4370 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4371 return;
4372
4373 // this is only item spell effect applied to main-hand weapon of target player (players in area)
4374 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4375 return;
4376
4377 Player* item_owner = unitTarget->ToPlayer();
4378 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
4379
4380 if (!item)
4381 return;
4382
4383 // must be equipped
4384 if (!item->IsEquipped())
4385 return;
4386
4387 if (m_spellInfo->Effects[effIndex].MiscValue)
4388 {
4389 uint32 enchant_id = m_spellInfo->Effects[effIndex].MiscValue;
4390 int32 duration = m_spellInfo->GetDuration(); //Try duration index first ..
4391 if (!duration)
4392 duration = damage;//+1; //Base points after ..
4393 if (!duration)
4394 duration = 10 * IN_MILLISECONDS; // 10 seconds for enchants which don't have listed duration
4395
4396 if (m_spellInfo->Id == 14792) // Venomhide Poison
4397 duration = 5 * MINUTE * IN_MILLISECONDS;
4398
4399 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
4400 if (!pEnchant)
4401 return;
4402
4403 // Always go to temp enchantment slot
4404 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
4405
4406 // Enchantment will not be applied if a different one already exists
4407 if (item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
4408 return;
4409
4410 // Apply the temporary enchantment
4411 item->SetEnchantment(slot, enchant_id, duration, 0, m_caster->GetGUID());
4412 item_owner->ApplyEnchantment(item, slot, true);
4413 }
4414}
4415
4416void Spell::EffectDisEnchant(SpellEffIndex /*effIndex*/)
4417{
4418 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4419 return;
4420
4421 if (!itemTarget || !itemTarget->GetTemplate()->DisenchantID)
4422 return;
4423
4424 if (Player* caster = m_caster->ToPlayer())
4425 {
4426 caster->UpdateCraftSkill(m_spellInfo->Id);
4427 caster->SendLoot(itemTarget->GetGUID(), LOOT_DISENCHANTING);
4428 }
4429
4430 // item will be removed at disenchanting end
4431}
4432
4433void Spell::EffectInebriate(SpellEffIndex /*effIndex*/)
4434{
4435 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4436 return;
4437
4438 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4439 return;
4440
4441 Player* player = unitTarget->ToPlayer();
4442 uint8 currentDrunk = player->GetDrunkValue();
4443 uint8 drunkMod = damage;
4444 if (currentDrunk + drunkMod > 100)
4445 {
4446 currentDrunk = 100;
4447 if (rand_chance() < 25.0f)
4448 player->CastSpell(player, 67468, false); // Drunken Vomit
4449 }
4450 else
4451 currentDrunk += drunkMod;
4452
4453 player->SetDrunkValue(currentDrunk, m_CastItem ? m_CastItem->GetEntry() : 0);
4454}
4455
4456void Spell::EffectFeedPet(SpellEffIndex effIndex)
4457{
4458 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4459 return;
4460
4461 Player* player = m_caster->ToPlayer();
4462 if (!player)
4463 return;
4464
4465 Item* foodItem = itemTarget;
4466 if (!foodItem)
4467 return;
4468
4469 Pet* pet = player->GetPet();
4470 if (!pet)
4471 return;
4472
4473 if (!pet->IsAlive())
4474 return;
4475
4476 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->ItemLevel);
4477 if (benefit <= 0)
4478 return;
4479
4480 ExecuteLogEffectDestroyItem(effIndex, foodItem->GetEntry());
4481
4482 uint32 count = 1;
4483 player->DestroyItemCount(foodItem, count, true);
4484 /// @todo fix crash when a spell has two effects, both pointed at the same item target
4485
4486 m_caster->CastCustomSpell(pet, m_spellInfo->Effects[effIndex].TriggerSpell, &benefit, NULL, NULL, true);
4487}
4488
4489void Spell::EffectDismissPet(SpellEffIndex effIndex)
4490{
4491 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4492 return;
4493
4494 if (!unitTarget || !unitTarget->IsPet())
4495 return;
4496
4497 Pet* pet = unitTarget->ToPet();
4498
4499 ExecuteLogEffectUnsummonObject(effIndex, pet);
4500 pet->GetOwner()->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
4501}
4502
4503void Spell::EffectSummonObject(SpellEffIndex effIndex)
4504{
4505 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4506 return;
4507
4508 uint32 go_id = m_spellInfo->Effects[effIndex].MiscValue;
4509 uint8 slot = m_spellInfo->Effects[effIndex].Effect - SPELL_EFFECT_SUMMON_OBJECT_SLOT1;
4510
4511 if (ObjectGuid guid = m_caster->m_ObjectSlot[slot])
4512 {
4513 if (GameObject* obj = m_caster->GetMap()->GetGameObject(guid))
4514 {
4515 // Recast case - null spell id to make auras not be removed on object remove from world
4516 if (m_spellInfo->Id == obj->GetSpellId())
4517 obj->SetSpellId(0);
4518 m_caster->RemoveGameObject(obj, true);
4519 }
4520 m_caster->m_ObjectSlot[slot].Clear();
4521 }
4522
4523 GameObject* go = new GameObject();
4524
4525 float x, y, z;
4526 // If dest location if present
4527 if (m_targets.HasDst())
4528 destTarget->GetPosition(x, y, z);
4529 // Summon in random point all other units if location present
4530 else
4531 m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
4532
4533 Map* map = m_caster->GetMap();
4534 if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
4535 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
4536 {
4537 delete go;
4538 return;
4539 }
4540
4541 //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
4542 int32 duration = m_spellInfo->GetDuration();
4543 go->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
4544 go->SetSpellId(m_spellInfo->Id);
4545 m_caster->AddGameObject(go);
4546
4547 ExecuteLogEffectSummonObject(effIndex, go);
4548
4549 map->AddToMap(go);
4550
4551 m_caster->m_ObjectSlot[slot] = go->GetGUID();
4552}
4553
4554void Spell::EffectResurrect(SpellEffIndex effIndex)
4555{
4556 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4557 return;
4558
4559 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4560 return;
4561
4562 if (unitTarget->IsAlive() || !unitTarget->IsInWorld())
4563 return;
4564
4565 Player* target = unitTarget->ToPlayer();
4566
4567 if (target->isResurrectRequested()) // already have one active request
4568 return;
4569
4570 uint32 health = target->CountPctFromMaxHealth(damage);
4571 uint32 mana = CalculatePct(target->GetMaxPower(POWER_MANA), damage);
4572
4573 ExecuteLogEffectResurrect(effIndex, target);
4574
4575 target->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
4576 SendResurrectRequest(target);
4577}
4578
4579void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex)
4580{
4581 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4582 return;
4583
4584 if (!unitTarget || !unitTarget->IsAlive())
4585 return;
4586
4587 if (unitTarget->m_extraAttacks)
4588 return;
4589
4590 unitTarget->m_extraAttacks = damage;
4591
4592 ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage);
4593}
4594
4595void Spell::EffectParry(SpellEffIndex /*effIndex*/)
4596{
4597 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4598 return;
4599
4600 if (m_caster->GetTypeId() == TYPEID_PLAYER)
4601 m_caster->ToPlayer()->SetCanParry(true);
4602}
4603
4604void Spell::EffectBlock(SpellEffIndex /*effIndex*/)
4605{
4606 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4607 return;
4608
4609 if (m_caster->GetTypeId() == TYPEID_PLAYER)
4610 m_caster->ToPlayer()->SetCanBlock(true);
4611}
4612
4613void Spell::EffectLeap(SpellEffIndex /*effIndex*/)
4614{
4615 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4616 return;
4617
4618 if (!unitTarget || unitTarget->IsInFlight())
4619 return;
4620
4621 if (!m_targets.HasDst())
4622 return;
4623
4624 Position pos = destTarget->GetPosition();
4625 unitTarget->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), unitTarget == m_caster);
4626}
4627
4628void Spell::EffectReputation(SpellEffIndex effIndex)
4629{
4630 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4631 return;
4632
4633 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4634 return;
4635
4636 Player* player = unitTarget->ToPlayer();
4637
4638 int32 repChange = damage;
4639
4640 uint32 factionId = m_spellInfo->Effects[effIndex].MiscValue;
4641
4642 FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId);
4643 if (!factionEntry)
4644 return;
4645
4646 repChange = player->CalculateReputationGain(REPUTATION_SOURCE_SPELL, 0, repChange, factionId);
4647
4648 player->GetReputationMgr().ModifyReputation(factionEntry, repChange);
4649}
4650
4651void Spell::EffectQuestComplete(SpellEffIndex effIndex)
4652{
4653 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4654 return;
4655
4656 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4657 return;
4658 Player* player = unitTarget->ToPlayer();
4659
4660 uint32 questId = m_spellInfo->Effects[effIndex].MiscValue;
4661 if (questId)
4662 {
4663 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
4664 if (!quest)
4665 return;
4666
4667 uint16 logSlot = player->FindQuestSlot(questId);
4668 if (logSlot < MAX_QUEST_LOG_SIZE)
4669 player->AreaExploredOrEventHappens(questId);
4670 else if (player->CanTakeQuest(quest, false)) // never rewarded before
4671 player->CompleteQuest(questId); // quest not in log - for internal use
4672 }
4673}
4674
4675void Spell::EffectForceDeselect(SpellEffIndex /*effIndex*/)
4676{
4677 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4678 return;
4679
4680 WorldPacket data(SMSG_CLEAR_TARGET, 8);
4681 data << uint64(m_caster->GetGUID());
4682 m_caster->SendMessageToSet(&data, true);
4683}
4684
4685void Spell::EffectSelfResurrect(SpellEffIndex effIndex)
4686{
4687 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4688 return;
4689
4690 if (!m_caster || m_caster->IsAlive())
4691 return;
4692 if (m_caster->GetTypeId() != TYPEID_PLAYER)
4693 return;
4694 if (!m_caster->IsInWorld())
4695 return;
4696
4697 uint32 health = 0;
4698 uint32 mana = 0;
4699
4700 // flat case
4701 if (damage < 0)
4702 {
4703 health = uint32(-damage);
4704 mana = m_spellInfo->Effects[effIndex].MiscValue;
4705 }
4706 // percent case
4707 else
4708 {
4709 health = m_caster->CountPctFromMaxHealth(damage);
4710 if (m_caster->GetMaxPower(POWER_MANA) > 0)
4711 mana = CalculatePct(m_caster->GetMaxPower(POWER_MANA), damage);
4712 }
4713
4714 Player* player = m_caster->ToPlayer();
4715 player->ResurrectPlayer(0.0f);
4716
4717 player->SetHealth(health);
4718 player->SetPower(POWER_MANA, mana);
4719 player->SetPower(POWER_RAGE, 0);
4720 player->SetPower(POWER_ENERGY, player->GetMaxPower(POWER_ENERGY));
4721
4722 player->SpawnCorpseBones();
4723}
4724
4725void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
4726{
4727 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4728 return;
4729
4730 if (unitTarget->GetTypeId() != TYPEID_UNIT)
4731 return;
4732 if (m_caster->GetTypeId() != TYPEID_PLAYER)
4733 return;
4734
4735 Creature* creature = unitTarget->ToCreature();
4736 int32 targetLevel = creature->getLevel();
4737
4738 uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
4739
4740 m_caster->ToPlayer()->SendLoot(creature->GetGUID(), LOOT_SKINNING);
4741 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
4742 creature->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
4743
4744 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
4745
4746 int32 skillValue = m_caster->ToPlayer()->GetPureSkillValue(skill);
4747
4748 // Double chances for elites
4749 m_caster->ToPlayer()->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1);
4750}
4751
4752void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
4753{
4754 if (!unitTarget)
4755 return;
4756
4757 if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
4758 {
4759 float speed = G3D::fuzzyGt(m_spellInfo->Speed, 0.0f) ? m_spellInfo->Speed : SPEED_CHARGE;
4760 // Spell is not using explicit target - no generated path
4761 if (m_preGeneratedPath.GetPathType() == PATHFIND_BLANK)
4762 {
4763 //unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
4764 Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
4765 m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speed);
4766 }
4767 else
4768 m_caster->GetMotionMaster()->MoveCharge(m_preGeneratedPath, speed);
4769 }
4770
4771 if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
4772 {
4773 // not all charge effects used in negative spells
4774 if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER)
4775 m_caster->Attack(unitTarget, true);
4776 }
4777}
4778
4779void Spell::EffectChargeDest(SpellEffIndex /*effIndex*/)
4780{
4781 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
4782 return;
4783
4784 if (m_targets.HasDst())
4785 {
4786 Position pos = destTarget->GetPosition();
4787 float angle = m_caster->GetRelativeAngle(pos.GetPositionX(), pos.GetPositionY());
4788 float dist = m_caster->GetDistance(pos);
4789 pos = m_caster->GetFirstCollisionPosition(dist, angle);
4790
4791 m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
4792 }
4793}
4794
4795void Spell::EffectKnockBack(SpellEffIndex effIndex)
4796{
4797 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4798 return;
4799
4800 if (!unitTarget)
4801 return;
4802
4803 if (Creature* creatureTarget = unitTarget->ToCreature())
4804 if (creatureTarget->isWorldBoss() || creatureTarget->IsDungeonBoss())
4805 return;
4806
4807 // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN
4808 if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
4809 return;
4810
4811 // Instantly interrupt non melee spells being cast
4812 if (unitTarget->IsNonMeleeSpellCast(true))
4813 unitTarget->InterruptNonMeleeSpells(true);
4814
4815 float ratio = 0.1f;
4816 float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue) * ratio;
4817 float speedz = float(damage) * ratio;
4818 if (speedxy < 0.1f && speedz < 0.1f)
4819 return;
4820
4821 float x, y;
4822 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_KNOCK_BACK_DEST)
4823 {
4824 if (m_targets.HasDst())
4825 destTarget->GetPosition(x, y);
4826 else
4827 return;
4828 }
4829 else //if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_KNOCK_BACK)
4830 {
4831 m_caster->GetPosition(x, y);
4832 }
4833
4834 unitTarget->KnockbackFrom(x, y, speedxy, speedz);
4835}
4836
4837void Spell::EffectLeapBack(SpellEffIndex effIndex)
4838{
4839 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
4840 return;
4841
4842 if (!unitTarget)
4843 return;
4844
4845 float speedxy = m_spellInfo->Effects[effIndex].MiscValue / 10.f;
4846 float speedz = damage/ 10.f;
4847 //1891: Disengage
4848 m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
4849}
4850
4851void Spell::EffectQuestClear(SpellEffIndex effIndex)
4852{
4853 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4854 return;
4855
4856 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4857 return;
4858 Player* player = unitTarget->ToPlayer();
4859
4860 uint32 quest_id = m_spellInfo->Effects[effIndex].MiscValue;
4861
4862 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
4863
4864 if (!quest)
4865 return;
4866
4867 // Player has never done this quest
4868 if (player->GetQuestStatus(quest_id) == QUEST_STATUS_NONE)
4869 return;
4870
4871 // remove all quest entries for 'entry' from quest log
4872 for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
4873 {
4874 uint32 logQuest = player->GetQuestSlotQuestId(slot);
4875 if (logQuest == quest_id)
4876 {
4877 player->SetQuestSlot(slot, 0);
4878
4879 // we ignore unequippable quest items in this case, it's still be equipped
4880 player->TakeQuestSourceItem(logQuest, false);
4881
4882 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
4883 {
4884 player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
4885 player->UpdatePvPState();
4886 }
4887 }
4888 }
4889
4890 player->RemoveActiveQuest(quest_id, false);
4891 player->RemoveRewardedQuest(quest_id);
4892}
4893
4894void Spell::EffectSendTaxi(SpellEffIndex effIndex)
4895{
4896 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4897 return;
4898
4899 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4900 return;
4901
4902 unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id);
4903}
4904
4905void Spell::EffectPullTowards(SpellEffIndex effIndex)
4906{
4907 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4908 return;
4909
4910 if (!unitTarget)
4911 return;
4912
4913 Position pos;
4914 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_PULL_TOWARDS_DEST)
4915 {
4916 if (m_targets.HasDst())
4917 pos.Relocate(*destTarget);
4918 else
4919 return;
4920 }
4921 else //if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_PULL_TOWARDS)
4922 {
4923 pos.Relocate(m_caster);
4924 }
4925
4926 float speedXY = float(m_spellInfo->Effects[effIndex].MiscValue) * 0.1f;
4927 float speedZ = unitTarget->GetDistance(pos) / speedXY * 0.5f * Movement::gravity;
4928
4929 unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ);
4930}
4931
4932void Spell::EffectDispelMechanic(SpellEffIndex effIndex)
4933{
4934 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
4935 return;
4936
4937 if (!unitTarget)
4938 return;
4939
4940 uint32 mechanic = m_spellInfo->Effects[effIndex].MiscValue;
4941 DispelList dispel_list;
4942 Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
4943 for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
4944 {
4945 Aura* aura = itr->second;
4946 if (!aura->GetApplicationOfTarget(unitTarget->GetGUID()))
4947 continue;
4948 if (roll_chance_i(aura->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster))))
4949 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & (1 << mechanic)))
4950 dispel_list.push_back(std::make_pair(aura->GetId(), aura->GetCasterGUID()));
4951 }
4952
4953 while (!dispel_list.empty())
4954 {
4955 unitTarget->RemoveAura(dispel_list.front().first, dispel_list.front().second, 0, AURA_REMOVE_BY_ENEMY_SPELL);
4956 dispel_list.pop_front();
4957 }
4958}
4959
4960void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/)
4961{
4962 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
4963 return;
4964
4965 if (damage < 0)
4966 return;
4967
4968 Player* player = m_caster->ToPlayer();
4969 if (!player)
4970 return;
4971
4972 // Maybe player dismissed dead pet or pet despawned?
4973 bool hadPet = true;
4974
4975 if (!player->GetPet())
4976 {
4977 // Position passed to SummonPet is irrelevant with current implementation,
4978 // pet will be relocated without using these coords in Pet::LoadPetFromDB
4979 player->SummonPet(0, 0.0f, 0.0f, 0.0f, 0.0f, SUMMON_PET, 0);
4980 hadPet = false;
4981 }
4982
4983 // TODO: Better to fail Hunter's "Revive Pet" at cast instead of here when casting ends
4984 Pet* pet = player->GetPet(); // Attempt to get current pet
4985 if (!pet || pet->IsAlive())
4986 return;
4987
4988 // If player did have a pet before reviving, teleport it
4989 if (hadPet)
4990 {
4991 // Reposition the pet's corpse before reviving so as not to grab aggro
4992 // We can use a different, more accurate version of GetClosePoint() since we have a pet
4993 float x, y, z; // Will be used later to reposition the pet if we have one
4994 player->GetClosePoint(x, y, z, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle());
4995 pet->NearTeleportTo(x, y, z, player->GetOrientation());
4996 pet->Relocate(x, y, z, player->GetOrientation()); // This is needed so SaveStayPosition() will get the proper coords.
4997 }
4998
4999 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
5000 pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5001 pet->setDeathState(ALIVE);
5002 pet->ClearUnitState(uint32(UNIT_STATE_ALL_STATE));
5003 pet->SetHealth(pet->CountPctFromMaxHealth(damage));
5004
5005 // Reset things for when the AI to takes over
5006 CharmInfo *ci = pet->GetCharmInfo();
5007 if (ci)
5008 {
5009 // In case the pet was at stay, we don't want it running back
5010 ci->SaveStayPosition();
5011 ci->SetIsAtStay(ci->HasCommandState(COMMAND_STAY));
5012
5013 ci->SetIsFollowing(false);
5014 ci->SetIsCommandAttack(false);
5015 ci->SetIsCommandFollow(false);
5016 ci->SetIsReturning(false);
5017 }
5018
5019 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5020}
5021
5022void Spell::EffectDestroyAllTotems(SpellEffIndex /*effIndex*/)
5023{
5024 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
5025 return;
5026
5027 int32 mana = 0;
5028 for (uint8 slot = SUMMON_SLOT_TOTEM; slot < MAX_TOTEM_SLOT; ++slot)
5029 {
5030 if (!m_caster->m_SummonSlot[slot])
5031 continue;
5032
5033 Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_SummonSlot[slot]);
5034 if (totem && totem->IsTotem())
5035 {
5036 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5037 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
5038 if (spellInfo)
5039 {
5040 mana += spellInfo->ManaCost;
5041 mana += int32(CalculatePct(m_caster->GetCreateMana(), spellInfo->ManaCostPercentage));
5042 }
5043 totem->ToTotem()->UnSummon();
5044 }
5045 }
5046 ApplyPct(mana, damage);
5047 if (mana)
5048 m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
5049}
5050
5051void Spell::EffectDurabilityDamage(SpellEffIndex effIndex)
5052{
5053 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5054 return;
5055
5056 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5057 return;
5058
5059 int32 slot = m_spellInfo->Effects[effIndex].MiscValue;
5060
5061 // -1 means all player equipped items and -2 all items
5062 if (slot < 0)
5063 {
5064 unitTarget->ToPlayer()->DurabilityPointsLossAll(damage, (slot < -1));
5065 ExecuteLogEffectDurabilityDamage(effIndex, unitTarget, -1, -1);
5066 return;
5067 }
5068
5069 // invalid slot value
5070 if (slot >= INVENTORY_SLOT_BAG_END)
5071 return;
5072
5073 if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
5074 {
5075 unitTarget->ToPlayer()->DurabilityPointsLoss(item, damage);
5076 ExecuteLogEffectDurabilityDamage(effIndex, unitTarget, item->GetEntry(), slot);
5077 }
5078}
5079
5080void Spell::EffectDurabilityDamagePCT(SpellEffIndex effIndex)
5081{
5082 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5083 return;
5084
5085 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5086 return;
5087
5088 int32 slot = m_spellInfo->Effects[effIndex].MiscValue;
5089
5090 // FIXME: some spells effects have value -1/-2
5091 // Possibly its mean -1 all player equipped items and -2 all items
5092 if (slot < 0)
5093 {
5094 unitTarget->ToPlayer()->DurabilityLossAll(float(damage) / 100.0f, (slot < -1));
5095 return;
5096 }
5097
5098 // invalid slot value
5099 if (slot >= INVENTORY_SLOT_BAG_END)
5100 return;
5101
5102 if (damage <= 0)
5103 return;
5104
5105 if (Item* item = unitTarget->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
5106 unitTarget->ToPlayer()->DurabilityLoss(item, float(damage) / 100.0f);
5107}
5108
5109void Spell::EffectModifyThreatPercent(SpellEffIndex /*effIndex*/)
5110{
5111 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5112 return;
5113
5114 if (!unitTarget)
5115 return;
5116
5117 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5118}
5119
5120void Spell::EffectTransmitted(SpellEffIndex effIndex)
5121{
5122 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
5123 return;
5124
5125 uint32 name_id = m_spellInfo->Effects[effIndex].MiscValue;
5126
5127 GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id);
5128
5129 if (!goinfo)
5130 {
5131 TC_LOG_ERROR("sql.sql", "Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast", name_id, m_spellInfo->Id);
5132 return;
5133 }
5134
5135 float fx, fy, fz;
5136
5137 if (m_targets.HasDst())
5138 destTarget->GetPosition(fx, fy, fz);
5139 //FIXME: this can be better check for most objects but still hack
5140 else if (m_spellInfo->Effects[effIndex].HasRadius() && m_spellInfo->Speed == 0)
5141 {
5142 float dis = m_spellInfo->Effects[effIndex].CalcRadius(m_originalCaster);
5143 m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
5144 }
5145 else
5146 {
5147 //GO is always friendly to it's creator, get range for friends
5148 float min_dis = m_spellInfo->GetMinRange(true);
5149 float max_dis = m_spellInfo->GetMaxRange(true);
5150 float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
5151
5152 m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
5153 }
5154
5155 Map* cMap = m_caster->GetMap();
5156 // if gameobject is summoning object, it should be spawned right on caster's position
5157 if (goinfo->type == GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5158 m_caster->GetPosition(fx, fy, fz);
5159
5160 GameObject* pGameObj = new GameObject;
5161
5162 if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5163 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
5164 {
5165 delete pGameObj;
5166 return;
5167 }
5168
5169 int32 duration = m_spellInfo->GetDuration();
5170
5171 switch (goinfo->type)
5172 {
5173 case GAMEOBJECT_TYPE_FISHINGNODE:
5174 {
5175 m_caster->SetChannelObjectGuid(pGameObj->GetGUID());
5176 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5177
5178 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5179 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5180 int32 lastSec = 0;
5181 switch (urand(0, 3))
5182 {
5183 case 0: lastSec = 3; break;
5184 case 1: lastSec = 7; break;
5185 case 2: lastSec = 13; break;
5186 case 3: lastSec = 17; break;
5187 }
5188
5189 duration = duration - lastSec*IN_MILLISECONDS + FISHING_BOBBER_READY_TIME*IN_MILLISECONDS;
5190 break;
5191 }
5192 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
5193 {
5194 if (m_caster->GetTypeId() == TYPEID_PLAYER)
5195 {
5196 pGameObj->AddUniqueUse(m_caster->ToPlayer());
5197 m_caster->AddGameObject(pGameObj); // will be removed at spell cancel
5198 }
5199 break;
5200 }
5201 case GAMEOBJECT_TYPE_DUEL_ARBITER: // 52991
5202 m_caster->AddGameObject(pGameObj);
5203 break;
5204 case GAMEOBJECT_TYPE_FISHINGHOLE:
5205 case GAMEOBJECT_TYPE_CHEST:
5206 default:
5207 break;
5208 }
5209
5210 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
5211
5212 pGameObj->SetOwnerGUID(m_caster->GetGUID());
5213
5214 //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
5215 pGameObj->SetSpellId(m_spellInfo->Id);
5216
5217 ExecuteLogEffectSummonObject(effIndex, pGameObj);
5218
5219 TC_LOG_DEBUG("spells", "AddObject at SpellEfects.cpp EffectTransmitted");
5220 //m_caster->AddGameObject(pGameObj);
5221 //m_ObjToDel.push_back(pGameObj);
5222
5223 cMap->AddToMap(pGameObj);
5224
5225 if (uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry())
5226 {
5227 GameObject* linkedGO = new GameObject;
5228 if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
5229 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
5230 {
5231 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0);
5232 //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel());
5233 linkedGO->SetSpellId(m_spellInfo->Id);
5234 linkedGO->SetOwnerGUID(m_caster->GetGUID());
5235
5236 ExecuteLogEffectSummonObject(effIndex, linkedGO);
5237
5238 linkedGO->GetMap()->AddToMap(linkedGO);
5239 }
5240 else
5241 {
5242 delete linkedGO;
5243 linkedGO = NULL;
5244 return;
5245 }
5246 }
5247}
5248
5249void Spell::EffectProspecting(SpellEffIndex /*effIndex*/)
5250{
5251 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5252 return;
5253
5254 Player* player = m_caster->ToPlayer();
5255 if (!player)
5256 return;
5257
5258 if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_PROTO_FLAG_PROSPECTABLE))
5259 return;
5260
5261 if (itemTarget->GetCount() < 5)
5262 return;
5263
5264 if (sWorld->getBoolConfig(CONFIG_SKILL_PROSPECTING))
5265 {
5266 uint32 SkillValue = player->GetPureSkillValue(SKILL_JEWELCRAFTING);
5267 uint32 reqSkillValue = itemTarget->GetTemplate()->RequiredSkillRank;
5268 player->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
5269 }
5270
5271 player->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
5272}
5273
5274void Spell::EffectMilling(SpellEffIndex /*effIndex*/)
5275{
5276 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5277 return;
5278
5279 Player* player = m_caster->ToPlayer();
5280 if (!player)
5281 return;
5282
5283 if (!itemTarget || !(itemTarget->GetTemplate()->Flags & ITEM_PROTO_FLAG_MILLABLE))
5284 return;
5285
5286 if (itemTarget->GetCount() < 5)
5287 return;
5288
5289 if (sWorld->getBoolConfig(CONFIG_SKILL_MILLING))
5290 {
5291 uint32 SkillValue = player->GetPureSkillValue(SKILL_INSCRIPTION);
5292 uint32 reqSkillValue = itemTarget->GetTemplate()->RequiredSkillRank;
5293 player->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
5294 }
5295
5296 player->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
5297}
5298
5299void Spell::EffectSkill(SpellEffIndex /*effIndex*/)
5300{
5301 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
5302 return;
5303
5304 TC_LOG_DEBUG("spells", "WORLD: SkillEFFECT");
5305}
5306
5307/* There is currently no need for this effect. We handle it in Battleground.cpp
5308 If we would handle the resurrection here, the spiritguide would instantly disappear as the
5309 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
5310 This is why we use a half sec delay between the visual effect and the resurrection itself */
5311void Spell::EffectSpiritHeal(SpellEffIndex /*effIndex*/)
5312{
5313 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5314 return;
5315
5316 /*
5317 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5318 return;
5319 if (!unitTarget->IsInWorld())
5320 return;
5321
5322 //m_spellInfo->Effects[i].BasePoints; == 99 (percent?)
5323 //unitTarget->ToPlayer()->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
5324 unitTarget->ToPlayer()->ResurrectPlayer(1.0f);
5325 unitTarget->ToPlayer()->SpawnCorpseBones();
5326 */
5327}
5328
5329// remove insignia spell effect
5330void Spell::EffectSkinPlayerCorpse(SpellEffIndex /*effIndex*/)
5331{
5332 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5333 return;
5334
5335 TC_LOG_DEBUG("spells", "Effect: SkinPlayerCorpse");
5336
5337 Player* player = m_caster->ToPlayer();
5338 Player* target = unitTarget->ToPlayer();
5339 if (!player || !target || target->IsAlive())
5340 return;
5341
5342 target->RemovedInsignia(player);
5343}
5344
5345void Spell::EffectStealBeneficialBuff(SpellEffIndex effIndex)
5346{
5347 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5348 return;
5349
5350 TC_LOG_DEBUG("spells", "Effect: StealBeneficialBuff");
5351
5352 if (!unitTarget || unitTarget == m_caster) // can't steal from self
5353 return;
5354
5355 DispelChargesList steal_list;
5356
5357 // Create dispel mask by dispel type
5358 uint32 dispelMask = SpellInfo::GetDispelMask(DispelType(m_spellInfo->Effects[effIndex].MiscValue));
5359 Unit::AuraMap const& auras = unitTarget->GetOwnedAuras();
5360 for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
5361 {
5362 Aura* aura = itr->second;
5363 AuraApplication * aurApp = aura->GetApplicationOfTarget(unitTarget->GetGUID());
5364 if (!aurApp)
5365 continue;
5366
5367 if ((aura->GetSpellInfo()->GetDispelMask()) & dispelMask)
5368 {
5369 // Need check for passive? this
5370 if (!aurApp->IsPositive() || aura->IsPassive() || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_NOT_STEALABLE))
5371 continue;
5372
5373 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
5374 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
5375 // Polymorph instead of 1 / (5 + 1) -> 16%.
5376 bool dispel_charges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
5377 uint8 charges = dispel_charges ? aura->GetCharges() : aura->GetStackAmount();
5378 if (charges > 0)
5379 steal_list.push_back(std::make_pair(aura, charges));
5380 }
5381 }
5382
5383 if (steal_list.empty())
5384 return;
5385
5386 // Ok if exist some buffs for dispel try dispel it
5387 uint32 failCount = 0;
5388 DispelList success_list;
5389 WorldPacket dataFail(SMSG_DISPEL_FAILED, 8+8+4+4+damage*4);
5390 // dispel N = damage buffs (or while exist buffs for dispel)
5391 for (int32 count = 0; count < damage && !steal_list.empty();)
5392 {
5393 // Random select buff for dispel
5394 DispelChargesList::iterator itr = steal_list.begin();
5395 std::advance(itr, urand(0, steal_list.size() - 1));
5396
5397 int32 chance = itr->first->CalcDispelChance(unitTarget, !unitTarget->IsFriendlyTo(m_caster));
5398 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
5399 if (!chance)
5400 {
5401 steal_list.erase(itr);
5402 continue;
5403 }
5404 else
5405 {
5406 if (roll_chance_i(chance))
5407 {
5408 success_list.push_back(std::make_pair(itr->first->GetId(), itr->first->GetCasterGUID()));
5409 --itr->second;
5410 if (itr->second <= 0)
5411 steal_list.erase(itr);
5412 }
5413 else
5414 {
5415 if (!failCount)
5416 {
5417 // Failed to dispell
5418 dataFail << uint64(m_caster->GetGUID()); // Caster GUID
5419 dataFail << uint64(unitTarget->GetGUID()); // Victim GUID
5420 dataFail << uint32(m_spellInfo->Id); // dispel spell id
5421 }
5422 ++failCount;
5423 dataFail << uint32(itr->first->GetId()); // Spell Id
5424 }
5425 ++count;
5426 }
5427 }
5428
5429 if (failCount)
5430 m_caster->SendMessageToSet(&dataFail, true);
5431
5432 if (success_list.empty())
5433 return;
5434
5435 WorldPacket dataSuccess(SMSG_SPELLSTEALLOG, 8+8+4+1+4+damage*5);
5436 dataSuccess << unitTarget->GetPackGUID(); // Victim GUID
5437 dataSuccess << m_caster->GetPackGUID(); // Caster GUID
5438 dataSuccess << uint32(m_spellInfo->Id); // dispel spell id
5439 dataSuccess << uint8(0); // not used
5440 dataSuccess << uint32(success_list.size()); // count
5441 for (DispelList::iterator itr = success_list.begin(); itr!=success_list.end(); ++itr)
5442 {
5443 dataSuccess << uint32(itr->first); // Spell Id
5444 dataSuccess << uint8(0); // 0 - steals !=0 transfers
5445 unitTarget->RemoveAurasDueToSpellBySteal(itr->first, itr->second, m_caster);
5446 }
5447 m_caster->SendMessageToSet(&dataSuccess, true);
5448}
5449
5450void Spell::EffectKillCreditPersonal(SpellEffIndex effIndex)
5451{
5452 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5453 return;
5454
5455 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5456 return;
5457
5458 unitTarget->ToPlayer()->KilledMonsterCredit(m_spellInfo->Effects[effIndex].MiscValue);
5459}
5460
5461void Spell::EffectKillCredit(SpellEffIndex effIndex)
5462{
5463 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5464 return;
5465
5466 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5467 return;
5468
5469 int32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue;
5470 if (!creatureEntry)
5471 {
5472 if (m_spellInfo->Id == 42793) // Burn Body
5473 creatureEntry = 24008; // Fallen Combatant
5474 }
5475
5476 if (creatureEntry)
5477 unitTarget->ToPlayer()->RewardPlayerAndGroupAtEvent(creatureEntry, unitTarget);
5478}
5479
5480void Spell::EffectQuestFail(SpellEffIndex effIndex)
5481{
5482 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5483 return;
5484
5485 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5486 return;
5487
5488 unitTarget->ToPlayer()->FailQuest(m_spellInfo->Effects[effIndex].MiscValue);
5489}
5490
5491void Spell::EffectQuestStart(SpellEffIndex effIndex)
5492{
5493 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5494 return;
5495
5496 if (!unitTarget)
5497 return;
5498
5499 Player* player = unitTarget->ToPlayer();
5500 if (!player)
5501 return;
5502
5503 if (Quest const* quest = sObjectMgr->GetQuestTemplate(m_spellInfo->Effects[effIndex].MiscValue))
5504 {
5505 if (!player->CanTakeQuest(quest, false))
5506 return;
5507
5508 if (quest->IsAutoAccept() && player->CanAddQuest(quest, false))
5509 player->AddQuestAndCheckCompletion(quest, player);
5510
5511 player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, player->GetGUID(), true);
5512 }
5513}
5514
5515void Spell::EffectActivateRune(SpellEffIndex effIndex)
5516{
5517 if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
5518 return;
5519
5520 if (m_caster->GetTypeId() != TYPEID_PLAYER)
5521 return;
5522
5523 Player* player = m_caster->ToPlayer();
5524
5525 if (player->getClass() != CLASS_DEATH_KNIGHT)
5526 return;
5527
5528 // needed later
5529 m_runesState = m_caster->ToPlayer()->GetRunesState();
5530
5531 uint32 count = damage;
5532 if (count == 0) count = 1;
5533 for (uint32 j = 0; j < MAX_RUNES && count > 0; ++j)
5534 {
5535 if (player->GetRuneCooldown(j) && player->GetCurrentRune(j) == RuneType(m_spellInfo->Effects[effIndex].MiscValue))
5536 {
5537 if (m_spellInfo->Id == 45529)
5538 if (player->GetBaseRune(j) != RuneType(m_spellInfo->Effects[effIndex].MiscValueB))
5539 continue;
5540 player->SetRuneCooldown(j, 0);
5541 --count;
5542 }
5543 }
5544
5545 // Blood Tap
5546 if (m_spellInfo->Id == 45529 && count > 0)
5547 {
5548 for (uint32 l = 0; l + 1 < MAX_RUNES && count > 0; ++l)
5549 {
5550 // Check if both runes are on cd as that is the only time when this needs to come into effect
5551 if ((player->GetRuneCooldown(l) && player->GetCurrentRune(l) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)) && (player->GetRuneCooldown(l+1) && player->GetCurrentRune(l+1) == RuneType(m_spellInfo->Effects[effIndex].MiscValueB)))
5552 {
5553 // Should always update the rune with the lowest cd
5554 if (l + 1 < MAX_RUNES && player->GetRuneCooldown(l) >= player->GetRuneCooldown(l+1))
5555 l++;
5556 player->SetRuneCooldown(l, 0);
5557 --count;
5558 // is needed to push through to the client that the rune is active
5559 player->ResyncRunes(MAX_RUNES);
5560 }
5561 else
5562 break;
5563 }
5564 }
5565
5566 // Empower rune weapon
5567 if (m_spellInfo->Id == 47568)
5568 {
5569 // Need to do this just once
5570 if (effIndex != 0)
5571 return;
5572
5573 for (uint32 i = 0; i < MAX_RUNES; ++i)
5574 {
5575 if (player->GetRuneCooldown(i) && (player->GetCurrentRune(i) == RUNE_FROST || player->GetCurrentRune(i) == RUNE_DEATH))
5576 player->SetRuneCooldown(i, 0);
5577 }
5578 }
5579}
5580
5581void Spell::EffectCreateTamedPet(SpellEffIndex effIndex)
5582{
5583 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5584 return;
5585
5586 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || unitTarget->GetPetGUID() || unitTarget->getClass() != CLASS_HUNTER)
5587 return;
5588
5589 uint32 creatureEntry = m_spellInfo->Effects[effIndex].MiscValue;
5590 Pet* pet = unitTarget->CreateTamedPetFrom(creatureEntry, m_spellInfo->Id);
5591 if (!pet)
5592 return;
5593
5594 // add to world
5595 pet->GetMap()->AddToMap(pet->ToCreature());
5596
5597 // unitTarget has pet now
5598 unitTarget->SetMinion(pet, true);
5599
5600 pet->InitTalentForLevel();
5601
5602 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5603 {
5604 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5605 unitTarget->ToPlayer()->PetSpellInitialize();
5606 }
5607}
5608
5609void Spell::EffectDiscoverTaxi(SpellEffIndex effIndex)
5610{
5611 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5612 return;
5613
5614 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5615 return;
5616 uint32 nodeid = m_spellInfo->Effects[effIndex].MiscValue;
5617 if (sTaxiNodesStore.LookupEntry(nodeid))
5618 unitTarget->ToPlayer()->GetSession()->SendDiscoverNewTaxiNode(nodeid);
5619}
5620
5621void Spell::EffectTitanGrip(SpellEffIndex /*effIndex*/)
5622{
5623 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
5624 return;
5625
5626 if (m_caster->GetTypeId() == TYPEID_PLAYER)
5627 m_caster->ToPlayer()->SetCanTitanGrip(true);
5628}
5629
5630void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/)
5631{
5632 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5633 return;
5634
5635 if (unitTarget)
5636 m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage));
5637}
5638
5639void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/)
5640{
5641 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5642 return;
5643
5644 if (!gameObjTarget)
5645 return;
5646
5647 Unit* caster = m_originalCaster;
5648 if (!caster)
5649 return;
5650
5651 FactionTemplateEntry const* casterFaction = caster->GetFactionTemplateEntry();
5652 FactionTemplateEntry const* targetFaction = sFactionTemplateStore.LookupEntry(gameObjTarget->GetUInt32Value(GAMEOBJECT_FACTION));
5653 // Do not allow to damage GO's of friendly factions (ie: Wintergrasp Walls/Ulduar Storm Beacons)
5654 if ((casterFaction && targetFaction && !casterFaction->IsFriendlyTo(*targetFaction)) || !targetFaction)
5655 gameObjTarget->ModifyHealth(-damage, caster, GetSpellInfo()->Id);
5656}
5657
5658void Spell::EffectGameObjectRepair(SpellEffIndex /*effIndex*/)
5659{
5660 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5661 return;
5662
5663 if (!gameObjTarget)
5664 return;
5665
5666 gameObjTarget->ModifyHealth(damage, m_caster);
5667}
5668
5669void Spell::EffectGameObjectSetDestructionState(SpellEffIndex effIndex)
5670{
5671 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5672 return;
5673
5674 if (!gameObjTarget || !m_originalCaster)
5675 return;
5676
5677 Player* player = m_originalCaster->GetCharmerOrOwnerPlayerOrPlayerItself();
5678 gameObjTarget->SetDestructibleState(GameObjectDestructibleState(m_spellInfo->Effects[effIndex].MiscValue), player, true);
5679}
5680
5681void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const* properties, uint32 numGuardians)
5682{
5683 Unit* caster = m_originalCaster;
5684 if (!caster)
5685 return;
5686
5687 if (caster->IsTotem())
5688 caster = caster->ToTotem()->GetOwner();
5689
5690 // in another case summon new
5691 uint8 level = caster->getLevel();
5692
5693 // level of pet summoned using engineering item based at engineering skill level
5694 if (m_CastItem && caster->GetTypeId() == TYPEID_PLAYER)
5695 if (ItemTemplate const* proto = m_CastItem->GetTemplate())
5696 if (proto->RequiredSkill == SKILL_ENGINEERING)
5697 if (uint16 skill202 = caster->ToPlayer()->GetSkillValue(SKILL_ENGINEERING))
5698 level = skill202 / 5;
5699
5700 float radius = 5.0f;
5701 int32 duration = m_spellInfo->GetDuration();
5702
5703 if (Player* modOwner = m_originalCaster->GetSpellModOwner())
5704 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
5705
5706 //TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
5707 Map* map = caster->GetMap();
5708
5709 for (uint32 count = 0; count < numGuardians; ++count)
5710 {
5711 Position pos;
5712 if (count == 0)
5713 pos = *destTarget;
5714 else
5715 // randomize position for multiple summons
5716 pos = m_caster->GetRandomPoint(*destTarget, radius);
5717
5718 TempSummon* summon = map->SummonCreature(entry, pos, properties, duration, caster, m_spellInfo->Id);
5719 if (!summon)
5720 return;
5721
5722 if (summon->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
5723 ((Guardian*)summon)->InitStatsForLevel(level);
5724
5725 if (properties && properties->Category == SUMMON_CATEGORY_ALLY)
5726 summon->setFaction(caster->getFaction());
5727
5728 if (summon->HasUnitTypeMask(UNIT_MASK_MINION) && m_targets.HasDst())
5729 ((Minion*)summon)->SetFollowAngle(m_caster->GetAngle(summon));
5730
5731 if (summon->GetEntry() == 27893)
5732 {
5733 if (uint32 weapon = m_caster->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID))
5734 {
5735 summon->SetDisplayId(11686); // modelid2
5736 summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon);
5737 }
5738 else
5739 summon->SetDisplayId(1126); // modelid1
5740 }
5741
5742 summon->AI()->EnterEvadeMode();
5743
5744 ExecuteLogEffectSummonObject(i, summon);
5745 }
5746}
5747
5748void Spell::EffectRenamePet(SpellEffIndex /*effIndex*/)
5749{
5750 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5751 return;
5752
5753 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
5754 !unitTarget->IsPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
5755 return;
5756
5757 unitTarget->SetByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED);
5758}
5759
5760void Spell::EffectPlayMusic(SpellEffIndex effIndex)
5761{
5762 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5763 return;
5764
5765 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5766 return;
5767
5768 uint32 soundid = m_spellInfo->Effects[effIndex].MiscValue;
5769
5770 if (!sSoundEntriesStore.LookupEntry(soundid))
5771 {
5772 TC_LOG_ERROR("spells", "EffectPlayMusic: Sound (Id: %u) not exist in spell %u.", soundid, m_spellInfo->Id);
5773 return;
5774 }
5775
5776 WorldPacket data(SMSG_PLAY_MUSIC, 4);
5777 data << uint32(soundid);
5778 unitTarget->ToPlayer()->GetSession()->SendPacket(&data);
5779}
5780
5781void Spell::EffectSpecCount(SpellEffIndex /*effIndex*/)
5782{
5783 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5784 return;
5785
5786 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5787 return;
5788
5789 unitTarget->ToPlayer()->UpdateSpecCount(damage);
5790}
5791
5792void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/)
5793{
5794 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5795 return;
5796
5797 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5798 return;
5799
5800 unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1
5801}
5802
5803void Spell::EffectPlaySound(SpellEffIndex effIndex)
5804{
5805 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5806 return;
5807
5808 if (!unitTarget)
5809 return;
5810
5811 Player* player = unitTarget->ToPlayer();
5812 if (!player)
5813 return;
5814
5815 switch (m_spellInfo->Id)
5816 {
5817 case 58730: // Restricted Flight Area
5818 case 58600: // Restricted Flight Area
5819 player->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE);
5820 break;
5821 default:
5822 break;
5823 }
5824
5825 uint32 soundId = m_spellInfo->Effects[effIndex].MiscValue;
5826
5827 if (!sSoundEntriesStore.LookupEntry(soundId))
5828 {
5829 TC_LOG_ERROR("spells", "EffectPlaySound: Sound (Id: %u) not exist in spell %u.", soundId, m_spellInfo->Id);
5830 return;
5831 }
5832
5833 player->PlayDirectSound(soundId, player);
5834}
5835
5836void Spell::EffectRemoveAura(SpellEffIndex effIndex)
5837{
5838 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5839 return;
5840
5841 if (!unitTarget)
5842 return;
5843 // there may be need of specifying casterguid of removed auras
5844 unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].TriggerSpell);
5845}
5846
5847void Spell::EffectCastButtons(SpellEffIndex effIndex)
5848{
5849 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
5850 return;
5851
5852 if (m_caster->GetTypeId() != TYPEID_PLAYER)
5853 return;
5854
5855 Player* p_caster = m_caster->ToPlayer();
5856 uint32 button_id = m_spellInfo->Effects[effIndex].MiscValue + 132;
5857 uint32 n_buttons = m_spellInfo->Effects[effIndex].MiscValueB;
5858
5859 for (; n_buttons; --n_buttons, ++button_id)
5860 {
5861 ActionButton const* ab = p_caster->GetActionButton(button_id);
5862 if (!ab || ab->GetType() != ACTION_BUTTON_SPELL)
5863 continue;
5864
5865 //! Action button data is unverified when it's set so it can be "hacked"
5866 //! to contain invalid spells, so filter here.
5867 uint32 spell_id = ab->GetAction();
5868 if (!spell_id)
5869 continue;
5870
5871 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
5872 if (!spellInfo)
5873 continue;
5874
5875 if (!p_caster->HasSpell(spell_id) || p_caster->GetSpellHistory()->HasCooldown(spell_id))
5876 continue;
5877
5878 if (!spellInfo->HasAttribute(SPELL_ATTR7_SUMMON_PLAYER_TOTEM))
5879 continue;
5880
5881 uint32 cost = spellInfo->CalcPowerCost(m_caster, spellInfo->GetSchoolMask());
5882 if (m_caster->GetPower(POWER_MANA) < cost)
5883 continue;
5884
5885 TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_IGNORE_GCD | TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_CAST_DIRECTLY);
5886 m_caster->CastSpell(m_caster, spell_id, triggerFlags);
5887 }
5888}
5889
5890void Spell::EffectRechargeManaGem(SpellEffIndex /*effIndex*/)
5891{
5892 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5893 return;
5894
5895 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5896 return;
5897
5898 Player* player = m_caster->ToPlayer();
5899
5900 if (!player)
5901 return;
5902
5903 uint32 item_id = m_spellInfo->Effects[EFFECT_0].ItemType;
5904
5905 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id);
5906 if (!pProto)
5907 {
5908 player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
5909 return;
5910 }
5911
5912 if (Item* pItem = player->GetItemByEntry(item_id))
5913 {
5914 for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
5915 pItem->SetSpellCharges(x, pProto->Spells[x].SpellCharges);
5916 pItem->SetState(ITEM_CHANGED, player);
5917 }
5918}
5919
5920void Spell::EffectBind(SpellEffIndex effIndex)
5921{
5922 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5923 return;
5924
5925 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5926 return;
5927
5928 Player* player = unitTarget->ToPlayer();
5929
5930 WorldLocation homeLoc;
5931 uint32 areaId = player->GetAreaId();
5932
5933 if (m_spellInfo->Effects[effIndex].MiscValue)
5934 areaId = m_spellInfo->Effects[effIndex].MiscValue;
5935
5936 if (m_targets.HasDst())
5937 homeLoc.WorldRelocate(*destTarget);
5938 else
5939 homeLoc = player->GetWorldLocation();
5940
5941 player->SetHomebind(homeLoc, areaId);
5942
5943 // binding
5944 WorldPacket data(SMSG_BINDPOINTUPDATE, 4 + 4 + 4 + 4 + 4);
5945 data << float(homeLoc.GetPositionX());
5946 data << float(homeLoc.GetPositionY());
5947 data << float(homeLoc.GetPositionZ());
5948 data << uint32(homeLoc.GetMapId());
5949 data << uint32(areaId);
5950 player->SendDirectMessage(&data);
5951
5952 TC_LOG_DEBUG("spells", "EffectBind: New homebind X: %f, Y: %f, Z: %f, MapId: %u, AreaId: %u",
5953 homeLoc.GetPositionX(), homeLoc.GetPositionY(), homeLoc.GetPositionZ(), homeLoc.GetMapId(), areaId);
5954
5955 // zone update
5956 data.Initialize(SMSG_PLAYERBOUND, 8 + 4);
5957 data << uint64(m_caster->GetGUID());
5958 data << uint32(areaId);
5959 player->SendDirectMessage(&data);
5960}
5961
5962void Spell::EffectSummonRaFFriend(SpellEffIndex effIndex)
5963{
5964 if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
5965 return;
5966
5967 if (m_caster->GetTypeId() != TYPEID_PLAYER || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5968 return;
5969
5970 m_caster->CastSpell(unitTarget, m_spellInfo->Effects[effIndex].TriggerSpell, true);
5971}