[7234] Now correct patch version: Use spell_loot_table for item creating in case...
[getmangos.git] / src / game / SpellEffects.cpp
blob948a88ec6407fc4759216336a9d003963ceaed9f
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
52 #include "Language.h"
53 #include "SocialMgr.h"
54 #include "Util.h"
55 #include "TemporarySummon.h"
56 #include "ScriptCalls.h"
57 #include "SkillDiscovery.h"
59 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
61 &Spell::EffectNULL, // 0
62 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
63 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
64 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
65 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
66 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
67 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
68 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
69 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
70 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
71 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
72 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
73 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
74 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
75 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
76 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
77 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
78 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
79 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
80 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
81 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
82 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
83 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
84 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
85 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
86 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
87 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
88 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
89 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
90 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
91 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
92 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
93 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
94 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
95 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
96 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
97 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
98 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
99 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
100 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
101 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
102 &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP
103 &Spell::EffectUnused, // 42 SPELL_EFFECT_JUMP2
104 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
105 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
106 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
107 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
108 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
109 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
110 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
111 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
112 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
113 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
114 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
115 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
116 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
117 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
118 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
119 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
120 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
121 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
122 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
123 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
124 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
125 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
126 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
127 &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
128 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
129 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
130 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
131 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
132 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
133 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
134 &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
135 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
136 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
137 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
138 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
139 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
140 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
141 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
142 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
143 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
144 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
145 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
146 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
147 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
148 &Spell::EffectUnused, // 87 SPELL_EFFECT_WMO_DAMAGE
149 &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
150 &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
151 &Spell::EffectUnused, // 90 SPELL_EFFECT_KILL_CREDIT
152 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
153 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
154 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
155 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
156 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
157 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
158 &Spell::EffectUnused, // 97 SPELL_EFFECT_97
159 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
160 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
161 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
162 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
163 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
164 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
165 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
166 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
167 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
168 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
169 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
170 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
171 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
172 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
173 &Spell::EffectUnused, //112 SPELL_EFFECT_112
174 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
175 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
176 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
177 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
178 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
179 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
180 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
181 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
182 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
183 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
184 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
185 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
186 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
187 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
188 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
189 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
190 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
191 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
192 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
193 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
194 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
195 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
196 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
197 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
198 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
199 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
200 &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
201 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
202 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
203 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
204 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
205 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
206 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
207 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
208 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
209 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
210 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
211 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
212 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
213 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
214 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
215 &Spell::EffectNULL, //154 unused
216 &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.
217 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
218 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
219 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
220 &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
223 void Spell::EffectNULL(uint32 /*i*/)
225 sLog.outDebug("WORLD: Spell Effect DUMMY");
228 void Spell::EffectUnused(uint32 /*i*/)
230 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
233 void Spell::EffectResurrectNew(uint32 i)
235 if(!unitTarget || unitTarget->isAlive())
236 return;
238 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
239 return;
241 if(!unitTarget->IsInWorld())
242 return;
244 Player* pTarget = ((Player*)unitTarget);
246 if(pTarget->isRessurectRequested()) // already have one active request
247 return;
249 uint32 health = damage;
250 uint32 mana = m_spellInfo->EffectMiscValue[i];
251 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
252 SendResurrectRequest(pTarget);
255 void Spell::EffectInstaKill(uint32 /*i*/)
257 if( !unitTarget || !unitTarget->isAlive() )
258 return;
260 // Demonic Sacrifice
261 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
263 uint32 entry = unitTarget->GetEntry();
264 uint32 spellID;
265 switch(entry)
267 case 416: spellID=18789; break; //imp
268 case 417: spellID=18792; break; //fellhunter
269 case 1860: spellID=18790; break; //void
270 case 1863: spellID=18791; break; //succubus
271 case 17252: spellID=35701; break; //fellguard
272 default:
273 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
274 return;
277 m_caster->CastSpell(m_caster,spellID,true);
280 if(m_caster==unitTarget) // prevent interrupt message
281 finish();
283 uint32 health = unitTarget->GetHealth();
284 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
287 void Spell::EffectEnvirinmentalDMG(uint32 i)
289 uint32 absorb = 0;
290 uint32 resist = 0;
292 // Note: this hack with damage replace required until GO casting not implemented
293 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
294 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
295 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
297 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
299 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
300 if(m_caster->GetTypeId() == TYPEID_PLAYER)
301 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
304 void Spell::EffectSchoolDMG(uint32 effect_idx)
306 if( unitTarget && unitTarget->isAlive())
308 switch(m_spellInfo->SpellFamilyName)
310 case SPELLFAMILY_GENERIC:
312 //Gore
313 if(m_spellInfo->SpellIconID == 2269 )
315 damage+= rand()%2 ? damage : 0;
318 switch(m_spellInfo->Id) // better way to check unknown
320 // Meteor like spells (divided damage to targets)
321 case 24340: case 26558: case 28884: // Meteor
322 case 36837: case 38903: case 41276: // Meteor
323 case 26789: // Shard of the Fallen Star
324 case 31436: // Malevolent Cleave
325 case 35181: // Dive Bomb
326 case 40810: case 43267: case 43268: // Saber Lash
327 case 42384: // Brutal Swipe
328 case 45150: // Meteor Slash
330 uint32 count = 0;
331 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
332 if(ihit->effectMask & (1<<effect_idx))
333 ++count;
335 damage /= count; // divide to all targets
336 break;
338 // percent from health with min
339 case 25599: // Thundercrash
341 damage = unitTarget->GetHealth() / 2;
342 if(damage < 200)
343 damage = 200;
344 break;
346 // Intercept (warrior spell trigger)
347 case 20253:
348 case 61491:
350 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
351 break;
354 break;
357 case SPELLFAMILY_MAGE:
359 // Arcane Blast
360 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
362 m_caster->CastSpell(m_caster,36032,true);
364 break;
366 case SPELLFAMILY_WARRIOR:
368 // Bloodthirst
369 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
371 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
373 // Shield Slam
374 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
375 damage += int32(m_caster->GetShieldBlockValue());
376 // Victory Rush
377 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
379 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
380 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
382 // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
383 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000400LL)
384 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
385 // Heroic Throw ${$m1+$AP*.50}
386 else if(m_spellInfo->SpellFamilyFlags & 0x0000000100000000LL)
387 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
388 // Shockwave ${$m3/100*$AP}
389 else if(m_spellInfo->SpellFamilyFlags & 0x0000800000000000LL)
391 int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
392 if (pct > 0)
393 damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
394 break;
396 break;
398 case SPELLFAMILY_WARLOCK:
400 // Incinerate Rank 1 & 2
401 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
403 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
404 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
405 damage += int32(damage*0.25f);
407 break;
409 case SPELLFAMILY_PRIEST:
411 // Shadow Word: Death - deals damage equal to damage done to caster
412 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
413 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
414 break;
416 case SPELLFAMILY_DRUID:
418 // Ferocious Bite
419 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
421 // converts each extra point of energy into ($f1+$AP/410) additional damage
422 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
423 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
424 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
425 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
426 m_caster->SetPower(POWER_ENERGY,0);
428 // Rake
429 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
431 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
433 // Swipe
434 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
436 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
438 //Mangle Bonus for the initial damage of Lacerate and Rake
439 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
440 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
442 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
443 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
444 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
446 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
447 break;
450 break;
452 case SPELLFAMILY_ROGUE:
454 // Envenom
455 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
457 // consume from stack dozes not more that have combo-points
458 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
460 Aura *poison = 0;
461 // Lookup for Deadly poison (only attacker applied)
462 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
463 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
464 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
465 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
466 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
468 poison = *itr;
469 break;
471 // count consumed deadly poison doses at target
472 if (poison)
474 uint32 spellId = poison->GetId();
475 uint32 doses = poison->GetStackAmount();
476 if (doses > combo)
477 doses = combo;
478 for (int i=0; i< doses; i++)
479 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
480 damage *= doses;
481 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
483 // Eviscerate and Envenom Bonus Damage (item set effect)
484 if(m_caster->GetDummyAura(37169))
485 damage += ((Player*)m_caster)->GetComboPoints()*40;
488 // Eviscerate
489 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
491 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
493 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
494 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
496 // Eviscerate and Envenom Bonus Damage (item set effect)
497 if(m_caster->GetDummyAura(37169))
498 damage += combo*40;
501 // Gouge
502 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
504 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.02f);
506 // Instant Poison
507 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
509 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
511 // Wound Poison
512 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
514 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
516 break;
518 case SPELLFAMILY_HUNTER:
520 // Mongoose Bite
521 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
523 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
525 // Counterattack
526 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
528 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
530 // Arcane Shot
531 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
533 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
535 // Steady Shot
536 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
538 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
539 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
541 // Explosive Trap Effect
542 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
544 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
546 break;
548 case SPELLFAMILY_PALADIN:
550 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
551 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
553 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
554 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
555 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
556 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
557 // Get stack of Holy Vengeance on the target added by caster
558 uint32 stacks = 0;
559 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
560 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
561 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
563 stacks = (*itr)->GetStackAmount();
564 break;
566 // + 10% for each application of Holy Vengeance on the target
567 if(stacks)
568 damage += damage * stacks * 10 /100;
570 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
571 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
573 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
574 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
575 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
576 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
578 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
579 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
581 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
582 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
583 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
584 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
586 // Hammer of the Righteous
587 else if(m_spellInfo->SpellFamilyFlags&0x0004000000000000LL)
589 // Add main hand dps * effect[2] amount
590 float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
591 int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
592 damage += count * int32(averange * 1000) / m_caster->GetAttackTime(BASE_ATTACK);
594 break;
598 if(damage >= 0)
599 m_damage+= damage;
603 void Spell::EffectDummy(uint32 i)
605 if(!unitTarget && !gameObjTarget && !itemTarget)
606 return;
608 // selection by spell family
609 switch(m_spellInfo->SpellFamilyName)
611 case SPELLFAMILY_GENERIC:
613 switch(m_spellInfo->Id )
615 case 8063: // Deviate Fish
617 if(m_caster->GetTypeId() != TYPEID_PLAYER)
618 return;
620 uint32 spell_id = 0;
621 switch(urand(1,5))
623 case 1: spell_id = 8064; break; // Sleepy
624 case 2: spell_id = 8065; break; // Invigorate
625 case 3: spell_id = 8066; break; // Shrink
626 case 4: spell_id = 8067; break; // Party Time!
627 case 5: spell_id = 8068; break; // Healthy Spirit
629 m_caster->CastSpell(m_caster,spell_id,true,NULL);
630 return;
632 case 8213: // Savory Deviate Delight
634 if(m_caster->GetTypeId() != TYPEID_PLAYER)
635 return;
637 uint32 spell_id = 0;
638 switch(urand(1,2))
640 // Flip Out - ninja
641 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
642 // Yaaarrrr - pirate
643 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
645 m_caster->CastSpell(m_caster,spell_id,true,NULL);
646 return;
648 case 8593: // Symbol of life (restore creature to life)
649 case 31225: // Shimmering Vessel (restore creature to life)
651 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
652 return;
653 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
654 return;
656 case 12162: // Deep wounds
657 case 12850: // (now good common check for this spells)
658 case 12868:
660 if(!unitTarget)
661 return;
663 float damage;
664 // DW should benefit of attack power, damage percent mods etc.
665 // TODO: check if using offhand damage is correct and if it should be divided by 2
666 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
667 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
668 else
669 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
671 switch (m_spellInfo->Id)
673 case 12850: damage *= 0.2f; break;
674 case 12162: damage *= 0.4f; break;
675 case 12868: damage *= 0.6f; break;
676 default:
677 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
678 return;
681 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
682 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
683 return;
685 case 13120: // net-o-matic
687 if(!unitTarget)
688 return;
690 uint32 spell_id = 0;
692 uint32 roll = urand(0, 99);
694 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
695 spell_id = 16566;
696 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
697 spell_id = 13119;
698 else // normal root
699 spell_id = 13099;
701 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
702 return;
704 case 13567: // Dummy Trigger
706 // can be used for different aura triggering, so select by aura
707 if(!m_triggeredByAuraSpell || !unitTarget)
708 return;
710 switch(m_triggeredByAuraSpell->Id)
712 case 26467: // Persistent Shield
713 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
714 break;
715 default:
716 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
717 break;
719 return;
721 case 15998: // Capture Worg Pup
722 case 29435: // Capture Female Kaliri Hatchling
724 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
725 return;
727 Creature* creatureTarget = (Creature*)unitTarget;
728 creatureTarget->setDeathState(JUST_DIED);
729 creatureTarget->RemoveCorpse();
730 creatureTarget->SetHealth(0); // just for nice GM-mode view
731 return;
733 case 16589: // Noggenfogger Elixir
735 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
736 return;
738 uint32 spell_id = 0;
739 switch(urand(1,3))
741 case 1: spell_id = 16595; break;
742 case 2: spell_id = 16593; break;
743 default:spell_id = 16591; break;
746 m_caster->CastSpell(m_caster,spell_id,true,NULL);
747 return;
749 case 17251: // Spirit Healer Res
751 if(!unitTarget || !m_originalCaster)
752 return;
754 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
756 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
757 data << unitTarget->GetGUID();
758 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
760 return;
762 case 17271: // Test Fetid Skull
764 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
765 return;
767 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
769 m_caster->CastSpell(m_caster,spell_id,true,NULL);
770 return;
772 case 20577: // Cannibalize
773 if (unitTarget)
774 m_caster->CastSpell(m_caster,20578,false,NULL);
775 return;
776 case 23019: // Crystal Prison Dummy DND
778 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
779 return;
781 Creature* creatureTarget = (Creature*)unitTarget;
782 if(creatureTarget->isPet())
783 return;
785 GameObject* pGameObj = new GameObject;
787 Map *map = creatureTarget->GetMap();
789 // create before death for get proper coordinates
790 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
791 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
792 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
794 delete pGameObj;
795 return;
798 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
799 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
800 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
801 pGameObj->SetSpellId(m_spellInfo->Id);
803 creatureTarget->setDeathState(JUST_DIED);
804 creatureTarget->RemoveCorpse();
805 creatureTarget->SetHealth(0); // just for nice GM-mode view
807 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
808 map->Add(pGameObj);
810 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
811 data << uint64(pGameObj->GetGUID());
812 m_caster->SendMessageToSet(&data,true);
814 return;
816 case 23074: // Arcanite Dragonling
817 if (!m_CastItem) return;
818 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
819 return;
820 case 23075: // Mithril Mechanical Dragonling
821 if (!m_CastItem) return;
822 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
823 return;
824 case 23076: // Mechanical Dragonling
825 if (!m_CastItem) return;
826 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
827 return;
828 case 23133: // Gnomish Battle Chicken
829 if (!m_CastItem) return;
830 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
831 return;
832 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
834 int32 r = irand(0, 119);
835 if ( r < 20 ) // 1/6 polymorph
836 m_caster->CastSpell(m_caster,23444,true);
837 else if ( r < 100 ) // 4/6 evil twin
838 m_caster->CastSpell(m_caster,23445,true);
839 else // 1/6 miss the target
840 m_caster->CastSpell(m_caster,36902,true);
841 return;
843 case 23453: // Ultrasafe Transporter: Gadgetzan
844 if ( roll_chance_i(50) ) // success
845 m_caster->CastSpell(m_caster,23441,true);
846 else // failure
847 m_caster->CastSpell(m_caster,23446,true);
848 return;
849 case 23645: // Hourglass Sand
850 m_caster->RemoveAurasDueToSpell(23170);
851 return;
852 case 23725: // Gift of Life (warrior bwl trinket)
853 m_caster->CastSpell(m_caster,23782,true);
854 m_caster->CastSpell(m_caster,23783,true);
855 return;
856 case 25860: // Reindeer Transformation
858 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
859 return;
861 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
862 float speed = m_caster->GetSpeedRate(MOVE_RUN);
864 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
866 //5 different spells used depending on mounted speed and if mount can fly or not
867 if (flyspeed >= 4.1f)
868 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
869 else if (flyspeed >= 3.8f)
870 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
871 else if (flyspeed >= 1.6f)
872 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
873 else if (speed >= 2.0f)
874 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
875 else
876 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
878 return;
880 //case 26074: // Holiday Cheer
881 // return; -- implemented at client side
882 case 28006: // Arcane Cloaking
884 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
885 m_caster->CastSpell(unitTarget,29294,true);
886 return;
888 case 28730: // Arcane Torrent (Mana)
890 Aura * dummy = m_caster->GetDummyAura(28734);
891 if (dummy)
893 int32 bp = damage * dummy->GetStackAmount();
894 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
895 m_caster->RemoveAurasDueToSpell(28734);
897 return;
899 case 29200: // Purify Helboar Meat
901 if( m_caster->GetTypeId() != TYPEID_PLAYER )
902 return;
904 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
906 m_caster->CastSpell(m_caster,spell_id,true,NULL);
907 return;
909 case 29858: // Soulshatter
910 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
911 m_caster->CastSpell(unitTarget,32835,true);
912 return;
913 case 30458: // Nigh Invulnerability
914 if (!m_CastItem) return;
915 if(roll_chance_i(86)) // success
916 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
917 else // backfire in 14% casts
918 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
919 return;
920 case 30507: // Poultryizer
921 if (!m_CastItem) return;
922 if(roll_chance_i(80)) // success
923 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
924 else // backfire 20%
925 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
926 return;
927 case 33060: // Make a Wish
929 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
930 return;
932 uint32 spell_id = 0;
934 switch(urand(1,5))
936 case 1: spell_id = 33053; break;
937 case 2: spell_id = 33057; break;
938 case 3: spell_id = 33059; break;
939 case 4: spell_id = 33062; break;
940 case 5: spell_id = 33064; break;
943 m_caster->CastSpell(m_caster,spell_id,true,NULL);
944 return;
946 case 35745:
948 uint32 spell_id;
949 switch(m_caster->GetAreaId())
951 case 3900: spell_id = 35743; break;
952 case 3742: spell_id = 35744; break;
953 default: return;
956 m_caster->CastSpell(m_caster,spell_id,true);
957 return;
959 case 37674: // Chaos Blast
961 if(!unitTarget)
962 return;
964 int32 basepoints0 = 100;
965 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
966 return;
968 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
970 // selecting one from Bloodstained Fortune item
971 uint32 newitemid;
972 switch(urand(1,20))
974 case 1: newitemid = 32688; break;
975 case 2: newitemid = 32689; break;
976 case 3: newitemid = 32690; break;
977 case 4: newitemid = 32691; break;
978 case 5: newitemid = 32692; break;
979 case 6: newitemid = 32693; break;
980 case 7: newitemid = 32700; break;
981 case 8: newitemid = 32701; break;
982 case 9: newitemid = 32702; break;
983 case 10: newitemid = 32703; break;
984 case 11: newitemid = 32704; break;
985 case 12: newitemid = 32705; break;
986 case 13: newitemid = 32706; break;
987 case 14: newitemid = 32707; break;
988 case 15: newitemid = 32708; break;
989 case 16: newitemid = 32709; break;
990 case 17: newitemid = 32710; break;
991 case 18: newitemid = 32711; break;
992 case 19: newitemid = 32712; break;
993 case 20: newitemid = 32713; break;
994 default:
995 return;
998 DoCreateItem(i,newitemid);
999 return;
1001 // Demon Broiled Surprise
1002 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1003 case 43723:
1005 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1006 return;
1008 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1009 return;
1012 case 44875: // Complete Raptor Capture
1014 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1015 return;
1017 Creature* creatureTarget = (Creature*)unitTarget;
1019 creatureTarget->setDeathState(JUST_DIED);
1020 creatureTarget->RemoveCorpse();
1021 creatureTarget->SetHealth(0); // just for nice GM-mode view
1023 //cast spell Raptor Capture Credit
1024 m_caster->CastSpell(m_caster,42337,true,NULL);
1025 return;
1027 case 37573: //Temporal Phase Modulator
1029 if(!unitTarget)
1030 return;
1032 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1033 if(!tempSummon)
1034 return;
1036 uint32 health = tempSummon->GetHealth();
1037 const uint32 entry_list[6] = {21821, 21820, 21817};
1039 float x = tempSummon->GetPositionX();
1040 float y = tempSummon->GetPositionY();
1041 float z = tempSummon->GetPositionZ();
1042 float o = tempSummon->GetOrientation();
1044 tempSummon->UnSummon();
1046 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1047 if (!pCreature)
1048 return;
1050 pCreature->SetHealth(health);
1052 if(pCreature->AI())
1053 pCreature->AI()->AttackStart(m_caster);
1055 return;
1057 case 34665: //Administer Antidote
1059 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1060 return;
1062 if(!unitTarget)
1063 return;
1065 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1066 if(!tempSummon)
1067 return;
1069 uint32 health = tempSummon->GetHealth();
1071 float x = tempSummon->GetPositionX();
1072 float y = tempSummon->GetPositionY();
1073 float z = tempSummon->GetPositionZ();
1074 float o = tempSummon->GetOrientation();
1075 tempSummon->UnSummon();
1077 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1078 if (!pCreature)
1079 return;
1081 pCreature->SetHealth(health);
1082 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1084 if (pCreature->AI())
1085 pCreature->AI()->AttackStart(m_caster);
1087 return;
1089 case 44997: // Converting Sentry
1091 //Converted Sentry Credit
1092 m_caster->CastSpell(m_caster, 45009, true);
1093 return;
1095 case 45030: // Impale Emissary
1097 // Emissary of Hate Credit
1098 m_caster->CastSpell(m_caster, 45088, true);
1099 return;
1101 case 50243: // Teach Language
1103 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1104 return;
1106 // spell has a 1/3 chance to trigger one of the below
1107 if(roll_chance_i(66))
1108 return;
1109 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1111 // 1000001 - gnomish binary
1112 m_caster->CastSpell(m_caster, 50242, true);
1114 else
1116 // 01001000 - goblin binary
1117 m_caster->CastSpell(m_caster, 50246, true);
1120 return;
1122 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1124 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1125 return;
1127 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1128 bg->EventPlayerDroppedFlag((Player*)m_caster);
1130 m_caster->CastSpell(m_caster, 30452, true, NULL);
1131 return;
1133 case 53341:
1134 case 53343:
1136 m_caster->CastSpell(m_caster,54586,true);
1137 return;
1141 //All IconID Check in there
1142 switch(m_spellInfo->SpellIconID)
1144 // Berserking (troll racial traits)
1145 case 1661:
1147 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1148 int32 melee_mod = 10;
1149 if (healthPerc <= 40)
1150 melee_mod = 30;
1151 if (healthPerc < 100 && healthPerc > 40)
1152 melee_mod = 10+(100-healthPerc)/3;
1154 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1155 int32 hasteModBasePoints1 = (5-melee_mod);
1156 int32 hasteModBasePoints2 = 5;
1158 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1159 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1160 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1161 return;
1164 break;
1166 case SPELLFAMILY_MAGE:
1167 switch(m_spellInfo->Id )
1169 case 11958: // Cold Snap
1171 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1172 return;
1174 // immediately finishes the cooldown on Frost spells
1175 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1176 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1178 if (itr->second->state == PLAYERSPELL_REMOVED)
1179 continue;
1181 uint32 classspell = itr->first;
1182 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1184 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1185 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1186 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1188 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1190 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1191 data << uint32(classspell);
1192 data << uint64(m_caster->GetGUID());
1193 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1196 return;
1198 case 32826:
1200 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1202 //Polymorph Cast Visual Rank 1
1203 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1204 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1206 return;
1209 break;
1210 case SPELLFAMILY_WARRIOR:
1211 // Charge
1212 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1214 int32 chargeBasePoints0 = damage;
1215 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1216 return;
1218 // Execute
1219 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1221 if(!unitTarget)
1222 return;
1224 uint32 rage = m_caster->GetPower(POWER_RAGE);
1225 // Glyph of Execution bonus
1226 if (Aura *aura = m_caster->GetDummyAura(58367))
1227 rage+=aura->GetModifier()->m_amount;
1229 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1230 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1231 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1232 m_caster->SetPower(POWER_RAGE,0);
1233 return;
1235 // Slam
1236 if(m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL)
1238 if(!unitTarget)
1239 return;
1240 m_damage+=m_caster->CalculateDamage(m_attackType, false);
1241 m_damage+=damage;
1242 return;
1244 switch(m_spellInfo->Id)
1246 // Warrior's Wrath
1247 case 21977:
1249 if(!unitTarget)
1250 return;
1251 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1252 return;
1254 // Last Stand
1255 case 12975:
1257 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1258 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1259 return;
1261 // Bloodthirst
1262 case 23881:
1264 m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
1265 return;
1268 break;
1269 case SPELLFAMILY_WARLOCK:
1270 // Life Tap
1271 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1273 // In 303 exist spirit depend
1274 uint32 spirit = m_caster->GetStat(STAT_SPIRIT);
1275 switch (m_spellInfo->Id)
1277 case 1454: damage+=spirit; break;
1278 case 1455: damage+=spirit*15/10; break;
1279 case 1456: damage+=spirit*2; break;
1280 case 11687: damage+=spirit*25/10; break;
1281 case 11688:
1282 case 11689:
1283 case 27222:
1284 case 57946: damage+=spirit*3; break;
1285 default:
1286 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1287 return;
1289 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1290 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1291 if(int32(unitTarget->GetHealth()) > damage)
1293 // Shouldn't Appear in Combat Log
1294 unitTarget->ModifyHealth(-damage);
1296 int32 mana = damage;
1297 // Improved Life Tap mod
1298 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1299 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1301 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1302 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1304 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1306 // Mana Feed
1307 int32 manaFeedVal = 0;
1308 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1309 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1311 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1312 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1314 if(manaFeedVal > 0)
1316 manaFeedVal = manaFeedVal * mana / 100;
1317 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1320 else
1321 SendCastResult(SPELL_FAILED_FIZZLE);
1322 return;
1324 break;
1325 case SPELLFAMILY_PRIEST:
1326 // Penance
1327 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1329 if (!unitTarget)
1330 return;
1332 int hurt = 0;
1333 int heal = 0;
1334 switch(m_spellInfo->Id)
1336 case 47540: hurt = 47758; heal = 47757; break;
1337 case 53005: hurt = 53001; heal = 52986; break;
1338 case 53006: hurt = 53002; heal = 52987; break;
1339 case 53007: hurt = 53003; heal = 52988; break;
1340 default:
1341 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1342 return;
1344 if (m_caster->IsFriendlyTo(unitTarget))
1345 m_caster->CastSpell(unitTarget, heal, true, 0);
1346 else
1347 m_caster->CastSpell(unitTarget, hurt, true, 0);
1348 return;
1350 switch(m_spellInfo->Id )
1352 case 28598: // Touch of Weakness triggered spell
1354 if(!unitTarget || !m_triggeredByAuraSpell)
1355 return;
1357 uint32 spellid = 0;
1358 switch(m_triggeredByAuraSpell->Id)
1360 case 2652: spellid = 2943; break; // Rank 1
1361 case 19261: spellid = 19249; break; // Rank 2
1362 case 19262: spellid = 19251; break; // Rank 3
1363 case 19264: spellid = 19252; break; // Rank 4
1364 case 19265: spellid = 19253; break; // Rank 5
1365 case 19266: spellid = 19254; break; // Rank 6
1366 case 25461: spellid = 25460; break; // Rank 7
1367 default:
1368 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1369 return;
1371 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1372 return;
1375 break;
1376 case SPELLFAMILY_DRUID:
1377 break;
1378 case SPELLFAMILY_ROGUE:
1379 switch(m_spellInfo->Id )
1381 case 5938: // Shiv
1383 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1384 return;
1386 Player *pCaster = ((Player*)m_caster);
1388 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1389 if(!item)
1390 return;
1392 // all poison enchantments is temporary
1393 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1394 if(!enchant_id)
1395 return;
1397 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1398 if(!pEnchant)
1399 return;
1401 for (int s=0;s<3;s++)
1403 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1404 continue;
1406 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1407 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1408 continue;
1410 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1413 m_caster->CastSpell(unitTarget, 5940, true);
1414 return;
1416 case 14185: // Preparation Rogue
1418 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1419 return;
1421 //immediately finishes the cooldown on certain Rogue abilities
1422 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1423 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1425 uint32 classspell = itr->first;
1426 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1428 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1430 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1432 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1433 data << uint32(classspell);
1434 data << uint64(m_caster->GetGUID());
1435 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1438 return;
1440 case 31231: // Cheat Death
1442 m_caster->CastSpell(m_caster,45182,true);
1443 return;
1446 break;
1447 case SPELLFAMILY_HUNTER:
1448 // Steady Shot
1449 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1451 if( !unitTarget || !unitTarget->isAlive())
1452 return;
1454 bool found = false;
1456 // check dazed affect
1457 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1458 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1460 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1462 found = true;
1463 break;
1467 if(found)
1468 m_damage+= damage;
1469 return;
1472 switch(m_spellInfo->Id)
1474 case 23989: //Readiness talent
1476 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1477 return;
1479 //immediately finishes the cooldown for hunter abilities
1480 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1481 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1483 uint32 classspell = itr->first;
1484 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1486 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1488 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1490 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1491 data << uint32(classspell);
1492 data << uint64(m_caster->GetGUID());
1493 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1496 return;
1498 case 37506: // Scatter Shot
1500 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1501 return;
1503 // break Auto Shot and autohit
1504 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1505 m_caster->AttackStop();
1506 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1507 return;
1510 break;
1511 case SPELLFAMILY_PALADIN:
1512 switch(m_spellInfo->SpellIconID)
1514 case 156: // Holy Shock
1516 if(!unitTarget)
1517 return;
1519 int hurt = 0;
1520 int heal = 0;
1522 switch(m_spellInfo->Id)
1524 case 20473: hurt = 25912; heal = 25914; break;
1525 case 20929: hurt = 25911; heal = 25913; break;
1526 case 20930: hurt = 25902; heal = 25903; break;
1527 case 27174: hurt = 27176; heal = 27175; break;
1528 case 33072: hurt = 33073; heal = 33074; break;
1529 case 48824: hurt = 48822; heal = 48820; break;
1530 case 48825: hurt = 48823; heal = 48821; break;
1531 default:
1532 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1533 return;
1536 if(m_caster->IsFriendlyTo(unitTarget))
1537 m_caster->CastSpell(unitTarget, heal, true, 0);
1538 else
1539 m_caster->CastSpell(unitTarget, hurt, true, 0);
1541 return;
1543 case 561: // Judgement of command
1545 if(!unitTarget)
1546 return;
1548 uint32 spell_id = m_currentBasePoints[i]+1;
1549 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1550 if(!spell_proto)
1551 return;
1553 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1555 // decreased damage (/2) for non-stunned target.
1556 SpellModifier *mod = new SpellModifier;
1557 mod->op = SPELLMOD_DAMAGE;
1558 mod->value = -50;
1559 mod->type = SPELLMOD_PCT;
1560 mod->spellId = m_spellInfo->Id;
1561 mod->mask = 0x0000020000000000LL;
1562 mod->mask2= 0LL;
1564 ((Player*)m_caster)->AddSpellMod(mod, true);
1565 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1566 // mod deleted
1567 ((Player*)m_caster)->AddSpellMod(mod, false);
1569 else
1570 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1572 return;
1576 switch(m_spellInfo->Id)
1578 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1579 case 20187:
1581 if (!unitTarget)
1582 return;
1583 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1584 return;
1586 case 31789: // Righteous Defense (step 1)
1588 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1590 // non-standard cast requirement check
1591 if (!unitTarget || unitTarget->getAttackers().empty())
1593 // clear cooldown at fail
1594 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1596 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1598 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1599 data << uint32(m_spellInfo->Id);
1600 data << uint64(m_caster->GetGUID());
1601 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1604 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1605 return;
1608 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1609 // Clear targets for eff 1
1610 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1611 ihit->effectMask &= ~(1<<1);
1613 // not empty (checked)
1614 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1616 // chance to be selected from list
1617 float chance = 100.0f/attackers.size();
1618 uint32 count=0;
1619 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1621 if(!roll_chance_f(chance))
1622 continue;
1623 ++count;
1624 AddUnitTarget((*aItr), 1);
1627 // now let next effect cast spell at each target.
1628 return;
1630 case 37877: // Blessing of Faith
1632 if(!unitTarget)
1633 return;
1635 uint32 spell_id = 0;
1636 switch(unitTarget->getClass())
1638 case CLASS_DRUID: spell_id = 37878; break;
1639 case CLASS_PALADIN: spell_id = 37879; break;
1640 case CLASS_PRIEST: spell_id = 37880; break;
1641 case CLASS_SHAMAN: spell_id = 37881; break;
1642 default: return; // ignore for not healing classes
1645 m_caster->CastSpell(m_caster,spell_id,true);
1646 return;
1649 break;
1650 case SPELLFAMILY_SHAMAN:
1651 //Shaman Rockbiter Weapon
1652 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1654 // TODO: use expect spell for enchant (if exist talent)
1655 // In 3.0.3 no mods present for rockbiter
1656 uint32 spell_id = 0;
1657 switch(m_spellInfo->Id)
1659 case 8017: spell_id = 36494; break; // Rank 1
1660 case 8018: spell_id = 36750; break; // Rank 2
1661 case 8019: spell_id = 36755; break; // Rank 3
1662 case 10399: spell_id = 36759; break; // Rank 4
1663 default:
1664 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1665 return;
1668 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1670 if(!spellInfo)
1672 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1673 return;
1676 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1677 return;
1679 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1681 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1683 if(item->IsFitToSpellRequirements(m_spellInfo))
1685 Spell *spell = new Spell(m_caster, spellInfo, true);
1687 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1688 // at calculation applied affect from Elemental Weapons talent
1689 // real enchantment damage-1
1690 spell->m_currentBasePoints[1] = damage-1;
1692 SpellCastTargets targets;
1693 targets.setItemTarget( item );
1694 spell->prepare(&targets);
1698 return;
1700 // Healing Stream Totem
1701 if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
1703 m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1704 return;
1706 // Mana Spring Totem
1707 if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
1709 if(unitTarget->getPowerType()!=POWER_MANA)
1710 return;
1711 m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1712 return;
1714 if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
1716 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1717 return;
1718 // Glyph of Mana Tide
1719 Unit *owner = m_caster->GetOwner();
1720 if (owner)
1721 if (Aura *dummy = owner->GetDummyAura(55441))
1722 damage+=dummy->GetModifier()->m_amount;
1723 // Regenerate 6% of Total Mana Every 3 secs
1724 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1725 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1726 return;
1728 // Lava Lash
1729 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1731 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1732 return;
1733 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1734 if (item)
1736 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1737 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1738 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1740 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1741 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1742 (*itr)->GetCastItemGUID() == item->GetGUID())
1744 m_damage += m_damage * damage / 100;
1745 return;
1749 return;
1751 break;
1754 // pet auras
1755 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1757 m_caster->AddPetAura(petSpell);
1758 return;
1762 void Spell::EffectTriggerSpellWithValue(uint32 i)
1764 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1766 // normal case
1767 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1769 if(!spellInfo)
1771 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1772 return;
1775 int32 bp = damage;
1776 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1779 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1781 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1782 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1784 if(!spellInfo)
1786 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1787 return;
1790 finish();
1791 Spell *spell = new Spell(m_caster, spellInfo, true);
1793 SpellCastTargets targets;
1794 targets.setUnitTarget( unitTarget);
1795 spell->prepare(&targets);
1797 m_caster->SetCurrentCastedSpell(spell);
1798 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1802 void Spell::EffectForceCast(uint32 i)
1804 if( !unitTarget )
1805 return;
1807 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1809 // normal case
1810 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1812 if(!spellInfo)
1814 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1815 return;
1818 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1821 void Spell::EffectTriggerSpell(uint32 i)
1823 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1825 // special cases
1826 switch(triggered_spell_id)
1828 // Vanish
1829 case 18461:
1831 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1832 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1833 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1835 // if this spell is given to NPC it must handle rest by it's own AI
1836 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1837 return;
1839 // get highest rank of the Stealth spell
1840 uint32 spellId = 0;
1841 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1842 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1844 // only highest rank is shown in spell book, so simply check if shown in spell book
1845 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1846 continue;
1848 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1849 if (!spellInfo)
1850 continue;
1852 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1854 spellId = spellInfo->Id;
1855 break;
1859 // no Stealth spell found
1860 if (!spellId)
1861 return;
1863 // reset cooldown on it if needed
1864 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1865 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1867 m_caster->CastSpell(m_caster, spellId, true);
1868 return;
1870 // just skip
1871 case 23770: // Sayge's Dark Fortune of *
1872 // not exist, common cooldown can be implemented in scripts if need.
1873 return;
1874 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1875 case 29284:
1877 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1878 if (!spell)
1879 return;
1881 for (int i=0; i < spell->StackAmount; ++i)
1882 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1883 return;
1885 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1886 case 29286:
1888 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1889 if (!spell)
1890 return;
1892 for (int i=0; i < spell->StackAmount; ++i)
1893 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1894 return;
1896 // Righteous Defense
1897 case 31980:
1899 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1900 return;
1902 // Cloak of Shadows
1903 case 35729 :
1905 Unit::AuraMap& Auras = m_caster->GetAuras();
1906 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1908 // remove all harmful spells on you...
1909 if( // ignore positive and passive auras
1910 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1911 // ignore physical auras
1912 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1914 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1915 iter = Auras.begin();
1918 return;
1920 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1921 case 41967:
1923 if (Unit *pet = m_caster->GetPet())
1924 pet->CastSpell(pet, 28305, true);
1925 return;
1929 // normal case
1930 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1932 if(!spellInfo)
1934 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1935 return;
1938 // some triggered spells require specific equipment
1939 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1941 // main hand weapon required
1942 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1944 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1946 // skip spell if no weapon in slot or broken
1947 if(!item || item->IsBroken() )
1948 return;
1950 // skip spell if weapon not fit to triggered spell
1951 if(!item->IsFitToSpellRequirements(spellInfo))
1952 return;
1955 // offhand hand weapon required
1956 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1958 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1960 // skip spell if no weapon in slot or broken
1961 if(!item || item->IsBroken() )
1962 return;
1964 // skip spell if weapon not fit to triggered spell
1965 if(!item->IsFitToSpellRequirements(spellInfo))
1966 return;
1970 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1971 bool instant = false;
1972 for(uint32 j = i+1; j < 3; ++j)
1974 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1976 instant = true;
1977 break;
1981 if(instant)
1983 if (unitTarget)
1984 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1986 else
1987 m_TriggerSpells.push_back(spellInfo);
1990 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1992 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1994 // normal case
1995 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1997 if(!spellInfo)
1999 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
2000 m_spellInfo->Id,effect_idx,triggered_spell_id);
2001 return;
2004 if (m_CastItem)
2005 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
2007 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
2010 void Spell::EffectTeleportUnits(uint32 i)
2012 if(!unitTarget || unitTarget->isInFlight())
2013 return;
2015 switch (m_spellInfo->EffectImplicitTargetB[i])
2017 case TARGET_INNKEEPER_COORDINATES:
2019 // Only players can teleport to innkeeper
2020 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2021 return;
2023 ((Player*)unitTarget)->TeleportTo(((Player*)unitTarget)->m_homebindMapId,((Player*)unitTarget)->m_homebindX,((Player*)unitTarget)->m_homebindY,((Player*)unitTarget)->m_homebindZ,unitTarget->GetOrientation(),unitTarget==m_caster ? TELE_TO_SPELL : 0);
2024 return;
2026 case TARGET_TABLE_X_Y_Z_COORDINATES:
2028 // TODO: Only players can teleport?
2029 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2030 return;
2031 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2032 if(!st)
2034 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
2035 return;
2037 ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0);
2038 break;
2040 case TARGET_BEHIND_VICTIM:
2042 // Get selected target for player (or victim for units)
2043 Unit *pTarget = NULL;
2044 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2045 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2046 else
2047 pTarget = m_caster->getVictim();
2048 // No target present - return
2049 if (!pTarget)
2050 return;
2051 // Init dest coordinates
2052 uint32 mapid = m_caster->GetMapId();
2053 float x = m_targets.m_destX;
2054 float y = m_targets.m_destY;
2055 float z = m_targets.m_destZ;
2056 float orientation = pTarget->GetOrientation();
2057 // Teleport
2058 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2059 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
2060 else
2062 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2063 WorldPacket data;
2064 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2065 unitTarget->SendMessageToSet(&data, false);
2067 return;
2069 default:
2071 // If not exist data for dest location - return
2072 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2074 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2075 return;
2077 // Init dest coordinates
2078 uint32 mapid = m_caster->GetMapId();
2079 float x = m_targets.m_destX;
2080 float y = m_targets.m_destY;
2081 float z = m_targets.m_destZ;
2082 float orientation = unitTarget->GetOrientation();
2083 // Teleport
2084 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2085 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
2086 else
2088 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2089 WorldPacket data;
2090 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2091 unitTarget->SendMessageToSet(&data, false);
2093 return;
2097 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2098 switch ( m_spellInfo->Id )
2100 // Dimensional Ripper - Everlook
2101 case 23442:
2103 int32 r = irand(0, 119);
2104 if ( r >= 70 ) // 7/12 success
2106 if ( r < 100 ) // 4/12 evil twin
2107 m_caster->CastSpell(m_caster,23445,true);
2108 else // 1/12 fire
2109 m_caster->CastSpell(m_caster,23449,true);
2111 return;
2113 // Ultrasafe Transporter: Toshley's Station
2114 case 36941:
2116 if ( roll_chance_i(50) ) // 50% success
2118 int32 rand_eff = urand(1,7);
2119 switch ( rand_eff )
2121 case 1:
2122 // soul split - evil
2123 m_caster->CastSpell(m_caster,36900,true);
2124 break;
2125 case 2:
2126 // soul split - good
2127 m_caster->CastSpell(m_caster,36901,true);
2128 break;
2129 case 3:
2130 // Increase the size
2131 m_caster->CastSpell(m_caster,36895,true);
2132 break;
2133 case 4:
2134 // Decrease the size
2135 m_caster->CastSpell(m_caster,36893,true);
2136 break;
2137 case 5:
2138 // Transform
2140 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2141 m_caster->CastSpell(m_caster,36897,true);
2142 else
2143 m_caster->CastSpell(m_caster,36899,true);
2144 break;
2146 case 6:
2147 // chicken
2148 m_caster->CastSpell(m_caster,36940,true);
2149 break;
2150 case 7:
2151 // evil twin
2152 m_caster->CastSpell(m_caster,23445,true);
2153 break;
2156 return;
2158 // Dimensional Ripper - Area 52
2159 case 36890:
2161 if ( roll_chance_i(50) ) // 50% success
2163 int32 rand_eff = urand(1,4);
2164 switch ( rand_eff )
2166 case 1:
2167 // soul split - evil
2168 m_caster->CastSpell(m_caster,36900,true);
2169 break;
2170 case 2:
2171 // soul split - good
2172 m_caster->CastSpell(m_caster,36901,true);
2173 break;
2174 case 3:
2175 // Increase the size
2176 m_caster->CastSpell(m_caster,36895,true);
2177 break;
2178 case 4:
2179 // Transform
2181 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2182 m_caster->CastSpell(m_caster,36897,true);
2183 else
2184 m_caster->CastSpell(m_caster,36899,true);
2185 break;
2189 return;
2194 void Spell::EffectApplyAura(uint32 i)
2196 if(!unitTarget)
2197 return;
2199 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2200 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2201 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2202 return;
2204 Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
2205 if(!caster)
2206 return;
2208 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2210 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2212 // Now Reduce spell duration using data received at spell hit
2213 int32 duration = Aur->GetAuraMaxDuration();
2214 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2215 Aur->setDiminishGroup(m_diminishGroup);
2217 // if Aura removed and deleted, do not continue.
2218 if(duration== 0 && !(Aur->IsPermanent()))
2220 delete Aur;
2221 return;
2224 if(duration != Aur->GetAuraMaxDuration())
2226 Aur->SetAuraMaxDuration(duration);
2227 Aur->SetAuraDuration(duration);
2230 bool added = unitTarget->AddAura(Aur);
2232 // Aura not added and deleted in AddAura call;
2233 if (!added)
2234 return;
2236 // found crash at character loading, broken pointer to Aur...
2237 // Aur was deleted in AddAura()...
2238 if(!Aur)
2239 return;
2241 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2242 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2243 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2246 void Spell::EffectUnlearnSpecialization( uint32 i )
2248 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2249 return;
2251 Player *_player = (Player*)unitTarget;
2252 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2254 _player->removeSpell(spellToUnlearn);
2256 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2259 void Spell::EffectPowerDrain(uint32 i)
2261 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2262 return;
2264 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2266 if(!unitTarget)
2267 return;
2268 if(!unitTarget->isAlive())
2269 return;
2270 if(unitTarget->getPowerType() != drain_power)
2271 return;
2272 if(damage < 0)
2273 return;
2275 uint32 curPower = unitTarget->GetPower(drain_power);
2277 //add spell damage bonus
2278 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2280 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2281 uint32 power = damage;
2282 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2283 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2285 int32 new_damage;
2286 if(curPower < power)
2287 new_damage = curPower;
2288 else
2289 new_damage = power;
2291 unitTarget->ModifyPower(drain_power,-new_damage);
2293 // Don`t restore from self drain
2294 if(drain_power == POWER_MANA && m_caster != unitTarget)
2296 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2297 if(manaMultiplier==0)
2298 manaMultiplier = 1;
2300 if(Player *modOwner = m_caster->GetSpellModOwner())
2301 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2303 int32 gain = int32(new_damage*manaMultiplier);
2305 m_caster->ModifyPower(POWER_MANA,gain);
2306 //send log
2307 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2311 void Spell::EffectSendEvent(uint32 EffectIndex)
2313 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2315 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2316 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2318 switch(m_spellInfo->Id)
2320 case 23333: // Pickup Horde Flag
2321 /*do not uncomment .
2322 if(bg->GetTypeID()==BATTLEGROUND_WS)
2323 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2324 sLog.outDebug("Send Event Horde Flag Picked Up");
2325 break;
2326 /* not used :
2327 case 23334: // Drop Horde Flag
2328 if(bg->GetTypeID()==BATTLEGROUND_WS)
2329 bg->EventPlayerDroppedFlag((Player*)m_caster);
2330 sLog.outDebug("Drop Horde Flag");
2331 break;
2333 case 23335: // Pickup Alliance Flag
2334 /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
2335 if(bg->GetTypeID()==BATTLEGROUND_WS)
2336 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2337 sLog.outDebug("Send Event Alliance Flag Picked Up");
2338 break;
2339 /* not used :
2340 case 23336: // Drop Alliance Flag
2341 if(bg->GetTypeID()==BATTLEGROUND_WS)
2342 bg->EventPlayerDroppedFlag((Player*)m_caster);
2343 sLog.outDebug("Drop Alliance Flag");
2344 break;
2345 case 23385: // Alliance Flag Returns
2346 if(bg->GetTypeID()==BATTLEGROUND_WS)
2347 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2348 sLog.outDebug("Alliance Flag Returned");
2349 break;
2350 case 23386: // Horde Flag Returns
2351 if(bg->GetTypeID()==BATTLEGROUND_WS)
2352 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2353 sLog.outDebug("Horde Flag Returned");
2354 break;*/
2355 case 34976:
2357 if(bg->GetTypeID()==BATTLEGROUND_EY)
2358 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2360 break;
2361 default:
2362 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2363 break;
2367 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2368 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2371 void Spell::EffectPowerBurn(uint32 i)
2373 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2374 return;
2376 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2378 if(!unitTarget)
2379 return;
2380 if(!unitTarget->isAlive())
2381 return;
2382 if(unitTarget->getPowerType()!=powertype)
2383 return;
2384 if(damage < 0)
2385 return;
2387 int32 curPower = int32(unitTarget->GetPower(powertype));
2389 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2390 uint32 power = damage;
2391 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2392 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2394 int32 new_damage = (curPower < power) ? curPower : power;
2396 unitTarget->ModifyPower(powertype,-new_damage);
2397 float multiplier = m_spellInfo->EffectMultipleValue[i];
2399 if(Player *modOwner = m_caster->GetSpellModOwner())
2400 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2402 new_damage = int32(new_damage*multiplier);
2403 m_damage+=new_damage;
2406 void Spell::EffectHeal( uint32 /*i*/ )
2408 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2410 // Try to get original caster
2411 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2413 // Skip if m_originalCaster not available
2414 if (!caster)
2415 return;
2417 int32 addhealth = damage;
2419 // Vessel of the Naaru (Vial of the Sunwell trinket)
2420 if (m_spellInfo->Id == 45064)
2422 // Amount of heal - depends from stacked Holy Energy
2423 int damageAmount = 0;
2424 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2425 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2426 if((*i)->GetId() == 45062)
2427 damageAmount+=(*i)->GetModifier()->m_amount;
2428 if (damageAmount)
2429 m_caster->RemoveAurasDueToSpell(45062);
2431 addhealth += damageAmount;
2433 // Swiftmend - consumes Regrowth or Rejuvenation
2434 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2436 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2437 // find most short by duration
2438 Aura *targetAura = NULL;
2439 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2441 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2442 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2444 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2445 targetAura = *i;
2449 if(!targetAura)
2451 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2452 return;
2454 int idx = 0;
2455 while(idx < 3)
2457 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2458 break;
2459 idx++;
2462 int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
2463 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2464 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2466 addhealth += tickheal * tickcount;
2468 else
2469 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
2471 m_healing+=addhealth;
2475 void Spell::EffectHealPct( uint32 /*i*/ )
2477 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2479 // Try to get original caster
2480 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2482 // Skip if m_originalCaster not available
2483 if (!caster)
2484 return;
2486 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2487 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2489 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2490 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2492 if(caster->GetTypeId()==TYPEID_PLAYER)
2493 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2494 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2498 void Spell::EffectHealMechanical( uint32 /*i*/ )
2500 // Mechanic creature type should be correctly checked by targetCreatureType field
2501 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2503 // Try to get original caster
2504 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2506 // Skip if m_originalCaster not available
2507 if (!caster)
2508 return;
2510 uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
2511 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2512 unitTarget->ModifyHealth( int32(damage) );
2516 void Spell::EffectHealthLeech(uint32 i)
2518 if(!unitTarget)
2519 return;
2520 if(!unitTarget->isAlive())
2521 return;
2523 if(damage < 0)
2524 return;
2526 sLog.outDebug("HealthLeech :%i", damage);
2528 float multiplier = m_spellInfo->EffectMultipleValue[i];
2530 if(Player *modOwner = m_caster->GetSpellModOwner())
2531 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2533 int32 new_damage = int32(damage*multiplier);
2534 uint32 curHealth = unitTarget->GetHealth();
2535 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2536 if(curHealth < new_damage)
2537 new_damage = curHealth;
2539 if(m_caster->isAlive())
2541 new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
2543 m_caster->ModifyHealth(new_damage);
2545 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2546 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2548 // m_healthLeech+=tmpvalue;
2549 // m_damage+=new_damage;
2552 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2554 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2555 return;
2557 Player* player = (Player*)unitTarget;
2559 uint32 newitemid = itemtype;
2560 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2561 if(!pProto)
2563 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2564 return;
2567 uint32 num_to_add;
2569 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2570 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2572 int32 basePoints = m_currentBasePoints[i];
2573 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2574 if (randomPoints)
2575 num_to_add = basePoints + irand(1, randomPoints);
2576 else
2577 num_to_add = basePoints + 1;
2579 else if (pProto->MaxCount == 1)
2580 num_to_add = 1;
2581 else if(player->getLevel() >= m_spellInfo->spellLevel)
2583 int32 basePoints = m_currentBasePoints[i];
2584 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2585 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2587 else
2588 num_to_add = 2;
2590 if (num_to_add < 1)
2591 num_to_add = 1;
2592 if (num_to_add > pProto->GetMaxStackSize())
2593 num_to_add = pProto->GetMaxStackSize();
2595 // init items_count to 1, since 1 item will be created regardless of specialization
2596 int items_count=1;
2597 // the chance to create additional items
2598 float additionalCreateChance=0.0f;
2599 // the maximum number of created additional items
2600 uint8 additionalMaxNum=0;
2601 // get the chance and maximum number for creating extra items
2602 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2604 // roll with this chance till we roll not to create or we create the max num
2605 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2606 ++items_count;
2609 // really will be created more items
2610 num_to_add *= items_count;
2612 // can the player store the new item?
2613 ItemPosCountVec dest;
2614 uint32 no_space = 0;
2615 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2616 if( msg != EQUIP_ERR_OK )
2618 // convert to possible store amount
2619 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2620 num_to_add -= no_space;
2621 else
2623 // if not created by another reason from full inventory or unique items amount limitation
2624 player->SendEquipError( msg, NULL, NULL );
2625 return;
2629 if(num_to_add)
2631 // create the new item and store it
2632 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2634 // was it successful? return error if not
2635 if(!pItem)
2637 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2638 return;
2641 // set the "Crafted by ..." property of the item
2642 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2643 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2645 // send info to the client
2646 if(pItem)
2647 player->SendNewItem(pItem, num_to_add, true, true);
2649 // we succeeded in creating at least one item, so a levelup is possible
2650 player->UpdateCraftSkill(m_spellInfo->Id);
2653 // for battleground marks send by mail if not add all expected
2654 if(no_space > 0 )
2656 BattleGroundTypeId bgType;
2657 switch(m_spellInfo->Id)
2659 case SPELL_AV_MARK_WINNER:
2660 case SPELL_AV_MARK_LOSER:
2661 bgType = BATTLEGROUND_AV;
2662 break;
2663 case SPELL_WS_MARK_WINNER:
2664 case SPELL_WS_MARK_LOSER:
2665 bgType = BATTLEGROUND_WS;
2666 break;
2667 case SPELL_AB_MARK_WINNER:
2668 case SPELL_AB_MARK_LOSER:
2669 bgType = BATTLEGROUND_AB;
2670 break;
2671 default:
2672 return;
2675 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2676 bg->SendRewardMarkByMail(player,newitemid,no_space);
2680 void Spell::EffectCreateItem(uint32 i)
2682 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2685 void Spell::EffectCreateItem2(uint32 i)
2687 // special case: generate using spell_loot_template
2688 if(!m_spellInfo->EffectItemType[i])
2690 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
2691 return;
2693 // create some random items
2694 ((Player*)m_caster)->AutoStoreLootItem(m_spellInfo->Id,LootTemplates_Spell);
2695 return;
2697 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2700 void Spell::EffectPersistentAA(uint32 i)
2702 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2704 if(Player* modOwner = m_caster->GetSpellModOwner())
2705 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2707 int32 duration = GetSpellDuration(m_spellInfo);
2708 DynamicObject* dynObj = new DynamicObject;
2709 if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius))
2711 delete dynObj;
2712 return;
2714 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2715 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2716 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2717 m_caster->AddDynObject(dynObj);
2718 dynObj->GetMap()->Add(dynObj);
2721 void Spell::EffectEnergize(uint32 i)
2723 if(!unitTarget)
2724 return;
2725 if(!unitTarget->isAlive())
2726 return;
2728 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2729 return;
2731 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2733 // Some level depends spells
2734 int multiplier = 0;
2735 int level_diff = 0;
2736 switch (m_spellInfo->Id)
2738 // Restore Energy
2739 case 9512:
2740 level_diff = m_caster->getLevel() - 40;
2741 multiplier = 2;
2742 break;
2743 // Blood Fury
2744 case 24571:
2745 level_diff = m_caster->getLevel() - 60;
2746 multiplier = 10;
2747 break;
2748 // Burst of Energy
2749 case 24532:
2750 level_diff = m_caster->getLevel() - 60;
2751 multiplier = 4;
2752 break;
2753 default:
2754 break;
2757 if (level_diff > 0)
2758 damage -= multiplier * level_diff;
2760 if(damage < 0)
2761 return;
2763 if(unitTarget->GetMaxPower(power) == 0)
2764 return;
2766 unitTarget->ModifyPower(power,damage);
2767 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2769 // Mad Alchemist's Potion
2770 if (m_spellInfo->Id == 45051)
2772 // find elixirs on target
2773 uint32 elixir_mask = 0;
2774 Unit::AuraMap& Auras = unitTarget->GetAuras();
2775 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2777 uint32 spell_id = itr->second->GetId();
2778 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2779 elixir_mask |= mask;
2782 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2783 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2785 // get all available elixirs by mask and spell level
2786 std::vector<uint32> elixirs;
2787 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2788 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2790 if (itr->second & elixir_mask)
2792 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2793 continue;
2795 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2796 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2797 continue;
2799 elixirs.push_back(itr->first);
2803 if (!elixirs.empty())
2805 // cast random elixir on target
2806 uint32 rand_spell = urand(0,elixirs.size()-1);
2807 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2812 void Spell::EffectEnergisePct(uint32 i)
2814 if(!unitTarget)
2815 return;
2816 if(!unitTarget->isAlive())
2817 return;
2819 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2820 return;
2822 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2824 uint32 maxPower = unitTarget->GetMaxPower(power);
2825 if(maxPower == 0)
2826 return;
2828 uint32 gain = damage * maxPower / 100;
2829 unitTarget->ModifyPower(power, gain);
2830 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2833 void Spell::SendLoot(uint64 guid, LootType loottype)
2835 Player* player = (Player*)m_caster;
2836 if (!player)
2837 return;
2839 if (gameObjTarget)
2841 if (Script->GOHello(player, gameObjTarget))
2842 return;
2844 switch (gameObjTarget->GetGoType())
2846 case GAMEOBJECT_TYPE_DOOR:
2847 case GAMEOBJECT_TYPE_BUTTON:
2848 gameObjTarget->UseDoorOrButton();
2849 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2850 return;
2852 case GAMEOBJECT_TYPE_QUESTGIVER:
2853 // start or end quest
2854 player->PrepareQuestMenu(guid);
2855 player->SendPreparedQuest(guid);
2856 return;
2858 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2859 // triggering linked GO
2860 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2861 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2862 return;
2864 case GAMEOBJECT_TYPE_GOOBER:
2865 // goober_scripts can be triggered if the player don't have the quest
2866 if (gameObjTarget->GetGOInfo()->goober.eventId)
2868 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2869 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2872 // cast goober spell
2873 if (gameObjTarget->GetGOInfo()->goober.questId)
2874 ///Quest require to be active for GO using
2875 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2876 return;
2878 gameObjTarget->AddUniqueUse(player);
2879 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2881 //TODO? Objective counting called without spell check but with quest objective check
2882 // if send spell id then this line will duplicate to spell casting call (double counting)
2883 // So we or have this line and not required in quest_template have reqSpellIdN
2884 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2885 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2887 // triggering linked GO
2888 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2889 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2891 return;
2893 case GAMEOBJECT_TYPE_CHEST:
2894 // TODO: possible must be moved to loot release (in different from linked triggering)
2895 if (gameObjTarget->GetGOInfo()->chest.eventId)
2897 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2898 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2901 // triggering linked GO
2902 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2903 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2905 // Don't return, let loots been taken
2909 // Send loot
2910 player->SendLoot(guid, loottype);
2913 void Spell::EffectOpenLock(uint32 /*i*/)
2915 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2917 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2918 return;
2921 Player* player = (Player*)m_caster;
2923 LootType loottype = LOOT_CORPSE;
2924 uint32 lockId = 0;
2925 uint64 guid = 0;
2927 // Get lockId
2928 if(gameObjTarget)
2930 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2931 // Arathi Basin banner opening !
2932 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2933 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2935 //isAllowUseBattleGroundObject() already called in CanCast()
2936 // in battleground check
2937 if(BattleGround *bg = player->GetBattleGround())
2939 // check if it's correct bg
2940 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2941 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2942 return;
2945 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2947 //isAllowUseBattleGroundObject() already called in CanCast()
2948 // in battleground check
2949 if(BattleGround *bg = player->GetBattleGround())
2951 if(bg->GetTypeID() == BATTLEGROUND_EY)
2952 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2953 return;
2956 lockId = gameObjTarget->GetLockId();
2957 guid = gameObjTarget->GetGUID();
2959 else if(itemTarget)
2961 lockId = itemTarget->GetProto()->LockID;
2962 guid = itemTarget->GetGUID();
2964 else
2966 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2967 return;
2970 if(!lockId) // possible case for GO and maybe for items.
2972 SendLoot(guid, loottype);
2973 return;
2976 // Get LockInfo
2977 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2979 if (!lockInfo)
2981 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2982 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2983 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2984 return;
2987 // check key
2988 for(int i = 0; i < 8; ++i)
2990 // Type==1 This means lockInfo->Index[i] is an item
2991 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2993 SendLoot(guid, loottype);
2994 return;
2998 uint32 SkillId = 0;
2999 // Check and skill-up skill
3000 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
3001 SkillId = m_spellInfo->EffectMiscValue[1];
3002 // pickpocketing spells
3003 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
3004 SkillId = SKILL_LOCKPICKING;
3006 // skill bonus provided by casting spell (mostly item spells)
3007 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
3009 uint32 reqSkillValue = lockInfo->Skill[0];
3011 if(lockInfo->Skill[1]) // required pick lock skill applying
3013 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
3015 SendCastResult(SPELL_FAILED_FIZZLE);
3016 return;
3019 reqSkillValue = lockInfo->Skill[1];
3021 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
3023 SendCastResult(SPELL_FAILED_BAD_TARGETS);
3024 return;
3027 if ( SkillId )
3029 loottype = LOOT_SKINNING;
3030 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
3032 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3033 return;
3036 // update skill if really known
3037 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3038 if(SkillValue) // non only item base skill
3040 if(gameObjTarget)
3042 // Allow one skill-up until respawned
3043 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3044 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3045 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3047 else if(itemTarget)
3049 // Do one skill-up
3050 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3051 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3056 SendLoot(guid, loottype);
3059 void Spell::EffectSummonChangeItem(uint32 i)
3061 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3062 return;
3064 Player *player = (Player*)m_caster;
3066 // applied only to using item
3067 if(!m_CastItem)
3068 return;
3070 // ... only to item in own inventory/bank/equip_slot
3071 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3072 return;
3074 uint32 newitemid = m_spellInfo->EffectItemType[i];
3075 if(!newitemid)
3076 return;
3078 uint16 pos = m_CastItem->GetPos();
3080 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3081 if( !pNewItem )
3082 return;
3084 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3086 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3087 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3090 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3092 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3093 player->DurabilityLoss(pNewItem, loosePercent);
3096 if( player->IsInventoryPos( pos ) )
3098 ItemPosCountVec dest;
3099 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3100 if( msg == EQUIP_ERR_OK )
3102 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3104 // prevent crash at access and unexpected charges counting with item update queue corrupt
3105 if(m_CastItem==m_targets.getItemTarget())
3106 m_targets.setItemTarget(NULL);
3108 m_CastItem = NULL;
3110 player->StoreItem( dest, pNewItem, true);
3111 return;
3114 else if( player->IsBankPos ( pos ) )
3116 ItemPosCountVec dest;
3117 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3118 if( msg == EQUIP_ERR_OK )
3120 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3122 // prevent crash at access and unexpected charges counting with item update queue corrupt
3123 if(m_CastItem==m_targets.getItemTarget())
3124 m_targets.setItemTarget(NULL);
3126 m_CastItem = NULL;
3128 player->BankItem( dest, pNewItem, true);
3129 return;
3132 else if( player->IsEquipmentPos ( pos ) )
3134 uint16 dest;
3135 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3136 if( msg == EQUIP_ERR_OK )
3138 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3140 // prevent crash at access and unexpected charges counting with item update queue corrupt
3141 if(m_CastItem==m_targets.getItemTarget())
3142 m_targets.setItemTarget(NULL);
3144 m_CastItem = NULL;
3146 player->EquipItem( dest, pNewItem, true);
3147 player->AutoUnequipOffhandIfNeed();
3148 return;
3152 // fail
3153 delete pNewItem;
3156 void Spell::EffectOpenSecretSafe(uint32 i)
3158 EffectOpenLock(i); //no difference for now
3161 void Spell::EffectProficiency(uint32 /*i*/)
3163 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3164 return;
3165 Player *p_target = (Player*)unitTarget;
3167 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3168 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3170 p_target->AddWeaponProficiency(subClassMask);
3171 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3173 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3175 p_target->AddArmorProficiency(subClassMask);
3176 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3180 void Spell::EffectApplyAreaAura(uint32 i)
3182 if(!unitTarget)
3183 return;
3184 if(!unitTarget->isAlive())
3185 return;
3187 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3188 unitTarget->AddAura(Aur);
3191 void Spell::EffectSummonType(uint32 i)
3193 switch(m_spellInfo->EffectMiscValueB[i])
3195 case SUMMON_TYPE_GUARDIAN:
3196 case SUMMON_TYPE_POSESSED:
3197 case SUMMON_TYPE_POSESSED2:
3198 case SUMMON_TYPE_FORCE_OF_NATURE:
3199 case SUMMON_TYPE_GUARDIAN2:
3200 EffectSummonGuardian(i);
3201 break;
3202 case SUMMON_TYPE_WILD:
3203 EffectSummonWild(i);
3204 break;
3205 case SUMMON_TYPE_DEMON:
3206 EffectSummonDemon(i);
3207 break;
3208 case SUMMON_TYPE_SUMMON:
3209 EffectSummon(i);
3210 break;
3211 case SUMMON_TYPE_CRITTER:
3212 case SUMMON_TYPE_CRITTER2:
3213 case SUMMON_TYPE_CRITTER3:
3214 EffectSummonCritter(i);
3215 break;
3216 case SUMMON_TYPE_TOTEM_SLOT1:
3217 case SUMMON_TYPE_TOTEM_SLOT2:
3218 case SUMMON_TYPE_TOTEM_SLOT3:
3219 case SUMMON_TYPE_TOTEM_SLOT4:
3220 case SUMMON_TYPE_TOTEM:
3221 EffectSummonTotem(i);
3222 break;
3223 case SUMMON_TYPE_UNKNOWN1:
3224 case SUMMON_TYPE_UNKNOWN2:
3225 case SUMMON_TYPE_UNKNOWN3:
3226 case SUMMON_TYPE_UNKNOWN4:
3227 case SUMMON_TYPE_UNKNOWN5:
3228 break;
3229 default:
3230 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3231 break;
3235 void Spell::EffectSummon(uint32 i)
3237 if(m_caster->GetPetGUID())
3238 return;
3240 if(!unitTarget)
3241 return;
3242 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3243 if(!pet_entry)
3244 return;
3245 uint32 level = m_caster->getLevel();
3246 Pet* spawnCreature = new Pet(SUMMON_PET);
3248 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3250 // set timer for unsummon
3251 int32 duration = GetSpellDuration(m_spellInfo);
3252 if(duration > 0)
3253 spawnCreature->SetDuration(duration);
3255 return;
3258 Map *map = m_caster->GetMap();
3259 uint32 pet_number = objmgr.GeneratePetNumber();
3260 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_caster->GetPhaseMask(),
3261 m_spellInfo->EffectMiscValue[i], pet_number))
3263 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3264 delete spawnCreature;
3265 return;
3268 // Summon in dest location
3269 float x,y,z;
3270 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3272 x = m_targets.m_destX;
3273 y = m_targets.m_destY;
3274 z = m_targets.m_destZ;
3276 else
3277 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3279 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3281 if(!spawnCreature->IsPositionValid())
3283 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3284 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3285 delete spawnCreature;
3286 return;
3289 // set timer for unsummon
3290 int32 duration = GetSpellDuration(m_spellInfo);
3291 if(duration > 0)
3292 spawnCreature->SetDuration(duration);
3294 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3295 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3296 spawnCreature->setPowerType(POWER_MANA);
3297 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3298 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3299 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3300 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3301 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3302 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3303 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3304 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3305 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3307 spawnCreature->InitStatsForLevel(level);
3309 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3311 spawnCreature->AIM_Initialize();
3312 spawnCreature->InitPetCreateSpells();
3313 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3314 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3316 std::string name = m_caster->GetName();
3317 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3318 spawnCreature->SetName( name );
3320 map->Add((Creature*)spawnCreature);
3322 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3324 m_caster->SetPet(spawnCreature);
3325 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3326 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3327 ((Player*)m_caster)->PetSpellInitialize();
3331 void Spell::EffectLearnSpell(uint32 i)
3333 if(!unitTarget)
3334 return;
3336 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3338 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3339 EffectLearnPetSpell(i);
3341 return;
3344 Player *player = (Player*)unitTarget;
3346 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3347 player->learnSpell(spellToLearn,false);
3349 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3352 void Spell::EffectDispel(uint32 i)
3354 if(!unitTarget)
3355 return;
3357 // Fill possible dispell list
3358 std::vector <Aura *> dispel_list;
3360 // Create dispel mask by dispel type
3361 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3362 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3363 Unit::AuraMap const& auras = unitTarget->GetAuras();
3364 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3366 Aura *aur = (*itr).second;
3367 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3369 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3371 bool positive = true;
3372 if (!aur->IsPositive())
3373 positive = false;
3374 else
3375 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3377 // do not remove positive auras if friendly target
3378 // negative auras if non-friendly target
3379 if(positive == unitTarget->IsFriendlyTo(m_caster))
3380 continue;
3382 // Add aura to dispel list
3383 dispel_list.push_back(aur);
3386 // Ok if exist some buffs for dispel try dispel it
3387 if (!dispel_list.empty())
3389 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3390 std::list < uint32 > fail_list; // spell_id
3391 int32 list_size = dispel_list.size();
3392 // Dispell N = damage buffs (or while exist buffs for dispel)
3393 for (int32 count=0; count < damage && list_size > 0; ++count)
3395 // Random select buff for dispel
3396 Aura *aur = dispel_list[urand(0, list_size-1)];
3398 SpellEntry const* spellInfo = aur->GetSpellProto();
3399 // Base dispel chance
3400 // TODO: possible chance depend from spell level??
3401 int32 miss_chance = 0;
3402 // Apply dispel mod from aura caster
3403 if (Unit *caster = aur->GetCaster())
3405 if ( Player* modOwner = caster->GetSpellModOwner() )
3406 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3408 // Try dispel
3409 if (roll_chance_i(miss_chance))
3410 fail_list.push_back(aur->GetId());
3411 else
3412 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3413 // Remove buff from list for prevent doubles
3414 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3416 Aura *dispeled = *j;
3417 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3419 j = dispel_list.erase(j);
3420 --list_size;
3422 else
3423 ++j;
3426 // Send success log and really remove auras
3427 if (!success_list.empty())
3429 int32 count = success_list.size();
3430 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3431 data.append(unitTarget->GetPackGUID()); // Victim GUID
3432 data.append(m_caster->GetPackGUID()); // Caster GUID
3433 data << uint32(m_spellInfo->Id); // Dispell spell id
3434 data << uint8(0); // not used
3435 data << uint32(count); // count
3436 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3438 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3439 data << uint32(spellInfo->Id); // Spell Id
3440 data << uint8(0); // 0 - dispeled !=0 cleansed
3441 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3443 m_caster->SendMessageToSet(&data, true);
3445 // On succes dispel
3446 // Devour Magic
3447 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3449 uint32 heal_spell = 0;
3450 switch (m_spellInfo->Id)
3452 case 19505: heal_spell = 19658; break;
3453 case 19731: heal_spell = 19732; break;
3454 case 19734: heal_spell = 19733; break;
3455 case 19736: heal_spell = 19735; break;
3456 case 27276: heal_spell = 27278; break;
3457 case 27277: heal_spell = 27279; break;
3458 default:
3459 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3460 break;
3462 if (heal_spell)
3463 m_caster->CastSpell(m_caster, heal_spell, true);
3466 // Send fail log to client
3467 if (!fail_list.empty())
3469 // Failed to dispell
3470 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3471 data << uint64(m_caster->GetGUID()); // Caster GUID
3472 data << uint64(unitTarget->GetGUID()); // Victim GUID
3473 data << uint32(m_spellInfo->Id); // Dispell spell id
3474 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3475 data << uint32(*j); // Spell Id
3476 m_caster->SendMessageToSet(&data, true);
3481 void Spell::EffectDualWield(uint32 /*i*/)
3483 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3484 ((Player*)unitTarget)->SetCanDualWield(true);
3487 void Spell::EffectPull(uint32 /*i*/)
3489 // TODO: create a proper pull towards distract spell center for distract
3490 sLog.outDebug("WORLD: Spell Effect DUMMY");
3493 void Spell::EffectDistract(uint32 /*i*/)
3495 // Check for possible target
3496 if (!unitTarget || unitTarget->isInCombat())
3497 return;
3499 // target must be OK to do this
3500 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3501 return;
3503 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3505 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3507 // For players just turn them
3508 WorldPacket data;
3509 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3510 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3511 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3513 else
3515 // Set creature Distracted, Stop it, And turn it
3516 unitTarget->SetOrientation(angle);
3517 unitTarget->StopMoving();
3518 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3522 void Spell::EffectPickPocket(uint32 /*i*/)
3524 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3525 return;
3527 // victim must be creature and attackable
3528 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3529 return;
3531 // victim have to be alive and humanoid or undead
3532 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3534 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3536 if (chance > irand(0, 19))
3538 // Stealing successful
3539 //sLog.outDebug("Sending loot from pickpocket");
3540 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3542 else
3544 // Reveal action + get attack
3545 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3546 if (((Creature*)unitTarget)->AI())
3547 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3552 void Spell::EffectAddFarsight(uint32 i)
3554 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3555 int32 duration = GetSpellDuration(m_spellInfo);
3556 DynamicObject* dynObj = new DynamicObject;
3557 if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius))
3559 delete dynObj;
3560 return;
3562 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3563 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3564 m_caster->AddDynObject(dynObj);
3565 dynObj->GetMap()->Add(dynObj);
3566 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3567 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3570 void Spell::EffectSummonWild(uint32 i)
3572 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3573 if(!creature_entry)
3574 return;
3576 uint32 level = m_caster->getLevel();
3578 // level of creature summoned using engineering item based at engineering skill level
3579 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3581 ItemPrototype const *proto = m_CastItem->GetProto();
3582 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3584 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3585 if(skill202)
3587 level = skill202/5;
3592 // select center of summon position
3593 float center_x = m_targets.m_destX;
3594 float center_y = m_targets.m_destY;
3595 float center_z = m_targets.m_destZ;
3597 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3599 int32 amount = damage > 0 ? damage : 1;
3601 for(int32 count = 0; count < amount; ++count)
3603 float px, py, pz;
3604 // If dest location if present
3605 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3607 // Summon 1 unit in dest location
3608 if (count == 0)
3610 px = m_targets.m_destX;
3611 py = m_targets.m_destY;
3612 pz = m_targets.m_destZ;
3614 // Summon in random point all other units if location present
3615 else
3616 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3618 // Summon if dest location not present near caster
3619 else
3620 m_caster->GetClosePoint(px,py,pz,3.0f);
3622 int32 duration = GetSpellDuration(m_spellInfo);
3624 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3626 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3630 void Spell::EffectSummonGuardian(uint32 i)
3632 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3633 if(!pet_entry)
3634 return;
3636 // Jewelery statue case (totem like)
3637 if(m_spellInfo->SpellIconID==2056)
3639 EffectSummonTotem(i);
3640 return;
3643 // set timer for unsummon
3644 int32 duration = GetSpellDuration(m_spellInfo);
3646 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3647 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3648 // so this code hack in fact
3649 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3650 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3651 return; // find old guardian, ignore summon
3653 // in another case summon new
3654 uint32 level = m_caster->getLevel();
3656 // level of pet summoned using engineering item based at engineering skill level
3657 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3659 ItemPrototype const *proto = m_CastItem->GetProto();
3660 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3662 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3663 if(skill202)
3665 level = skill202/5;
3670 // select center of summon position
3671 float center_x = m_targets.m_destX;
3672 float center_y = m_targets.m_destY;
3673 float center_z = m_targets.m_destZ;
3675 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3677 int32 amount = damage > 0 ? damage : 1;
3679 for(int32 count = 0; count < amount; ++count)
3681 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3683 Map *map = m_caster->GetMap();
3684 uint32 pet_number = objmgr.GeneratePetNumber();
3685 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_caster->GetPhaseMask(),
3686 m_spellInfo->EffectMiscValue[i], pet_number))
3688 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3689 delete spawnCreature;
3690 return;
3693 float px, py, pz;
3694 // If dest location if present
3695 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3697 // Summon 1 unit in dest location
3698 if (count == 0)
3700 px = m_targets.m_destX;
3701 py = m_targets.m_destY;
3702 pz = m_targets.m_destZ;
3704 // Summon in random point all other units if location present
3705 else
3706 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3708 // Summon if dest location not present near caster
3709 else
3710 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3712 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3714 if(!spawnCreature->IsPositionValid())
3716 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3717 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3718 delete spawnCreature;
3719 return;
3722 if(duration > 0)
3723 spawnCreature->SetDuration(duration);
3725 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3726 spawnCreature->setPowerType(POWER_MANA);
3727 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3728 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3729 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3730 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3731 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3732 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3733 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3735 spawnCreature->InitStatsForLevel(level);
3736 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3738 spawnCreature->AIM_Initialize();
3740 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3741 ((Player*)m_caster)->AddGuardian(spawnCreature);
3743 map->Add((Creature*)spawnCreature);
3747 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3749 if(!unitTarget)
3750 return;
3752 if(unitTarget->isInFlight())
3753 return;
3755 uint32 mapid = m_caster->GetMapId();
3756 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3758 float fx,fy,fz;
3759 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3761 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3762 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
3763 else
3764 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3767 void Spell::EffectLearnSkill(uint32 i)
3769 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3770 return;
3772 if(damage < 0)
3773 return;
3775 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3776 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3777 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3780 void Spell::EffectAddHonor(uint32 /*i*/)
3782 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3783 return;
3785 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3787 // TODO: find formula for honor reward based on player's level!
3789 // now fixed only for level 70 players:
3790 if (((Player*)unitTarget)->getLevel() == 70)
3791 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3794 void Spell::EffectTradeSkill(uint32 /*i*/)
3796 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3797 return;
3798 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3799 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3800 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3803 void Spell::EffectEnchantItemPerm(uint32 effect_idx)
3805 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3806 return;
3807 if (!itemTarget)
3808 return;
3810 Player* p_caster = (Player*)m_caster;
3812 // not grow at item use at item case
3813 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3815 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3816 if (!enchant_id)
3817 return;
3819 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3820 if(!pEnchant)
3821 return;
3823 // item can be in trade slot and have owner diff. from caster
3824 Player* item_owner = itemTarget->GetOwner();
3825 if(!item_owner)
3826 return;
3828 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3830 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3831 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3832 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3833 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3836 // remove old enchanting before applying new if equipped
3837 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3839 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3841 // add new enchanting if equipped
3842 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3845 void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
3847 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3848 return;
3849 if (!itemTarget)
3850 return;
3852 Player* p_caster = (Player*)m_caster;
3854 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3855 if (!enchant_id)
3856 return;
3858 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3859 if(!pEnchant)
3860 return;
3862 // support only enchantings with add socket in this slot
3864 bool add_socket = false;
3865 for(int i = 0; i < 3; ++i)
3867 if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
3869 add_socket = true;
3870 break;
3873 if(!add_socket)
3875 sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (u), not suppoted yet.",
3876 m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
3877 return;
3881 // item can be in trade slot and have owner diff. from caster
3882 Player* item_owner = itemTarget->GetOwner();
3883 if(!item_owner)
3884 return;
3886 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3888 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3889 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3890 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3891 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3894 // remove old enchanting before applying new if equipped
3895 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
3897 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3899 // add new enchanting if equipped
3900 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
3903 void Spell::EffectEnchantItemTmp(uint32 i)
3905 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3906 return;
3908 Player* p_caster = (Player*)m_caster;
3910 if(!itemTarget)
3911 return;
3913 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3915 // Shaman Rockbiter Weapon
3916 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3918 int32 enchnting_damage = m_currentBasePoints[1]+1;
3920 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3921 // with already applied percent bonus from Elemental Weapons talent
3922 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3923 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3924 switch(enchnting_damage)
3926 // Rank 1
3927 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3928 // Rank 2
3929 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3930 case 5: enchant_id = 3025; break; // 20%
3931 // Rank 3
3932 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3933 case 7: enchant_id = 3027; break; // 20%
3934 // Rank 4
3935 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3936 case 10: enchant_id = 503; break; // 14%
3937 case 11: enchant_id = 3031; break; // 20%
3938 // Rank 5
3939 case 15: enchant_id = 3035; break; // 0%
3940 case 16: enchant_id = 1663; break; // 7%
3941 case 17: enchant_id = 3033; break; // 14%
3942 case 18: enchant_id = 3034; break; // 20%
3943 // Rank 6
3944 case 28: enchant_id = 3038; break; // 0%
3945 case 29: enchant_id = 683; break; // 7%
3946 case 31: enchant_id = 3036; break; // 14%
3947 case 33: enchant_id = 3037; break; // 20%
3948 // Rank 7
3949 case 40: enchant_id = 3041; break; // 0%
3950 case 42: enchant_id = 1664; break; // 7%
3951 case 45: enchant_id = 3039; break; // 14%
3952 case 48: enchant_id = 3040; break; // 20%
3953 // Rank 8
3954 case 49: enchant_id = 3044; break; // 0%
3955 case 52: enchant_id = 2632; break; // 7%
3956 case 55: enchant_id = 3042; break; // 14%
3957 case 58: enchant_id = 3043; break; // 20%
3958 // Rank 9
3959 case 62: enchant_id = 2633; break; // 0%
3960 case 66: enchant_id = 3018; break; // 7%
3961 case 70: enchant_id = 3019; break; // 14%
3962 case 74: enchant_id = 3020; break; // 20%
3963 default:
3964 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3965 return;
3969 if (!enchant_id)
3971 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3972 return;
3975 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3976 if(!pEnchant)
3978 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3979 return;
3982 // select enchantment duration
3983 uint32 duration;
3985 // rogue family enchantments exception by duration
3986 if(m_spellInfo->Id==38615)
3987 duration = 1800; // 30 mins
3988 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3989 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3990 duration = 3600; // 1 hour
3991 // shaman family enchantments
3992 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3993 duration = 1800; // 30 mins
3994 // other cases with this SpellVisual already selected
3995 else if(m_spellInfo->SpellVisual[0]==215)
3996 duration = 1800; // 30 mins
3997 // some fishing pole bonuses
3998 else if(m_spellInfo->SpellVisual[0]==563)
3999 duration = 600; // 10 mins
4000 // shaman rockbiter enchantments
4001 else if(m_spellInfo->SpellVisual[0]==0)
4002 duration = 1800; // 30 mins
4003 else if(m_spellInfo->Id==29702)
4004 duration = 300; // 5 mins
4005 else if(m_spellInfo->Id==37360)
4006 duration = 300; // 5 mins
4007 // default case
4008 else
4009 duration = 3600; // 1 hour
4011 // item can be in trade slot and have owner diff. from caster
4012 Player* item_owner = itemTarget->GetOwner();
4013 if(!item_owner)
4014 return;
4016 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
4018 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
4019 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
4020 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
4021 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
4024 // remove old enchanting before applying new if equipped
4025 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
4027 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
4029 // add new enchanting if equipped
4030 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
4033 void Spell::EffectTameCreature(uint32 /*i*/)
4035 if(m_caster->GetPetGUID())
4036 return;
4038 if(!unitTarget)
4039 return;
4041 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
4042 return;
4044 Creature* creatureTarget = (Creature*)unitTarget;
4046 if(creatureTarget->isPet())
4047 return;
4049 if(m_caster->getClass() != CLASS_HUNTER)
4050 return;
4052 // cast finish successfully
4053 //SendChannelUpdate(0);
4054 finish();
4056 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
4058 // kill original creature
4059 creatureTarget->setDeathState(JUST_DIED);
4060 creatureTarget->RemoveCorpse();
4061 creatureTarget->SetHealth(0); // just for nice GM-mode view
4063 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4065 // prepare visual effect for levelup
4066 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4068 // add to world
4069 pet->GetMap()->Add((Creature*)pet);
4071 // visual effect for levelup
4072 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4074 // caster have pet now
4075 m_caster->SetPet(pet);
4077 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4079 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4080 ((Player*)m_caster)->PetSpellInitialize();
4084 void Spell::EffectSummonPet(uint32 i)
4086 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4088 Pet *OldSummon = m_caster->GetPet();
4090 // if pet requested type already exist
4091 if( OldSummon )
4093 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4095 // pet in corpse state can't be summoned
4096 if( OldSummon->isDead() )
4097 return;
4099 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4100 OldSummon->SetMapId(m_caster->GetMapId());
4102 float px, py, pz;
4103 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4105 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4106 m_caster->GetMap()->Add((Creature*)OldSummon);
4108 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4110 ((Player*)m_caster)->PetSpellInitialize();
4112 return;
4115 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4116 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4117 else
4118 return;
4121 Pet* NewSummon = new Pet;
4123 // petentry==0 for hunter "call pet" (current pet summoned if any)
4124 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4126 if(NewSummon->getPetType()==SUMMON_PET)
4128 // Remove Demonic Sacrifice auras (known pet)
4129 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4130 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4132 if((*itr)->GetModifier()->m_miscvalue==2228)
4134 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4135 itr = auraClassScripts.begin();
4137 else
4138 ++itr;
4142 return;
4145 // not error in case fail hunter call pet
4146 if(!petentry)
4148 delete NewSummon;
4149 return;
4152 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4154 if(!cInfo)
4156 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4157 delete NewSummon;
4158 return;
4161 Map *map = m_caster->GetMap();
4162 uint32 pet_number = objmgr.GeneratePetNumber();
4163 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
4164 petentry, pet_number))
4166 delete NewSummon;
4167 return;
4170 float px, py, pz;
4171 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4173 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4175 if(!NewSummon->IsPositionValid())
4177 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4178 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4179 delete NewSummon;
4180 return;
4183 uint32 petlevel = m_caster->getLevel();
4184 NewSummon->setPetType(SUMMON_PET);
4186 uint32 faction = m_caster->getFaction();
4187 if(m_caster->GetTypeId() == TYPEID_UNIT)
4189 if ( ((Creature*)m_caster)->isTotem() )
4190 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4191 else
4192 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4195 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4196 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4197 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4198 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4199 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4200 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4201 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4202 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4203 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4204 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4206 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4207 // this enables pet details window (Shift+P)
4209 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4210 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4211 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4213 NewSummon->InitStatsForLevel(petlevel);
4214 NewSummon->InitPetCreateSpells();
4215 NewSummon->InitTalentForLevel();
4217 if(NewSummon->getPetType()==SUMMON_PET)
4219 // Remove Demonic Sacrifice auras (new pet)
4220 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4221 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4223 if((*itr)->GetModifier()->m_miscvalue==2228)
4225 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4226 itr = auraClassScripts.begin();
4228 else
4229 ++itr;
4232 // generate new name for summon pet
4233 std::string new_name=objmgr.GeneratePetName(petentry);
4234 if(!new_name.empty())
4235 NewSummon->SetName(new_name);
4237 else if(NewSummon->getPetType()==HUNTER_PET)
4238 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4240 NewSummon->AIM_Initialize();
4241 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4242 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4244 map->Add((Creature*)NewSummon);
4246 m_caster->SetPet(NewSummon);
4247 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4249 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4251 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4252 ((Player*)m_caster)->PetSpellInitialize();
4256 void Spell::EffectLearnPetSpell(uint32 i)
4258 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4259 return;
4261 Player *_player = (Player*)m_caster;
4263 Pet *pet = _player->GetPet();
4264 if(!pet)
4265 return;
4266 if(!pet->isAlive())
4267 return;
4269 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4270 if(!learn_spellproto)
4271 return;
4273 pet->learnSpell(learn_spellproto->Id);
4275 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4276 _player->PetSpellInitialize();
4279 void Spell::EffectTaunt(uint32 /*i*/)
4281 // this effect use before aura Taunt apply for prevent taunt already attacking target
4282 // for spell as marked "non effective at already attacking target"
4283 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4285 if(unitTarget->getVictim()==m_caster)
4287 SendCastResult(SPELL_FAILED_DONT_REPORT);
4288 return;
4292 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4293 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4294 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4297 void Spell::EffectWeaponDmg(uint32 i)
4299 if(!unitTarget)
4300 return;
4301 if(!unitTarget->isAlive())
4302 return;
4304 // multiple weapon dmg effect workaround
4305 // execute only the last weapon damage
4306 // and handle all effects at once
4307 for (int j = 0; j < 3; j++)
4309 switch(m_spellInfo->Effect[j])
4311 case SPELL_EFFECT_WEAPON_DAMAGE:
4312 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4313 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4314 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4315 if (j < i) // we must calculate only at last weapon effect
4316 return;
4317 break;
4321 // some spell specific modifiers
4322 bool customBonusDamagePercentMod = false;
4323 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4324 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4325 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4326 bool normalized = false;
4328 int32 spell_bonus = 0; // bonus specific for spell
4329 switch(m_spellInfo->SpellFamilyName)
4331 case SPELLFAMILY_WARRIOR:
4333 // Whirlwind, single only spell with 2 weapon white damage apply if have
4334 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4336 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4337 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4339 // Devastate bonus and sunder armor refresh
4340 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4342 uint32 stack = 0;
4343 // Need refresh all Sunder Armor auras from this caster
4344 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4345 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4347 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4348 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4349 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4350 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4352 (*itr).second->RefreshAura();
4353 stack = (*itr).second->GetStackAmount();
4356 if (stack)
4357 spell_bonus += stack * CalculateDamage(2, unitTarget);
4359 break;
4361 case SPELLFAMILY_ROGUE:
4363 // Ambush
4364 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4366 customBonusDamagePercentMod = true;
4367 bonusDamagePercentMod = 2.5f; // 250%
4369 // Mutilate (for each hand)
4370 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4372 bool found = false;
4373 // fast check
4374 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4375 found = true;
4376 // full aura scan
4377 else
4379 Unit::AuraMap const& auras = unitTarget->GetAuras();
4380 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4382 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4384 found = true;
4385 break;
4390 if(found)
4391 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4393 break;
4395 case SPELLFAMILY_PALADIN:
4397 // Seal of Command - receive benefit from Spell Damage and Healing
4398 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4400 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4401 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4403 break;
4405 case SPELLFAMILY_SHAMAN:
4407 // Skyshatter Harness item set bonus
4408 // Stormstrike
4409 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4411 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4412 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4414 // Stormstrike AP Buff
4415 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4417 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4418 break;
4425 int32 fixed_bonus = 0;
4426 for (int j = 0; j < 3; j++)
4428 switch(m_spellInfo->Effect[j])
4430 case SPELL_EFFECT_WEAPON_DAMAGE:
4431 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4432 fixed_bonus += CalculateDamage(j,unitTarget);
4433 break;
4434 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4435 fixed_bonus += CalculateDamage(j,unitTarget);
4436 normalized = true;
4437 break;
4438 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4439 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4441 // applied only to prev.effects fixed damage
4442 if(customBonusDamagePercentMod)
4443 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4444 else
4445 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4446 break;
4447 default:
4448 break; // not weapon damage effect, just skip
4452 // non-weapon damage
4453 int32 bonus = spell_bonus + fixed_bonus;
4455 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4456 if(bonus)
4458 UnitMods unitMod;
4459 switch(m_attackType)
4461 default:
4462 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4463 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4464 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4467 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4468 bonus = int32(bonus*weapon_total_pct);
4471 // + weapon damage with applied weapon% dmg to base weapon damage in call
4472 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4474 // total damage
4475 bonus = int32(bonus*totalDamagePercentMod);
4477 // prevent negative damage
4478 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4480 // Add melee damage bonuses (also check for negative)
4481 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4482 m_damage+= eff_damage;
4484 // Hemorrhage
4485 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4487 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4488 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4491 // Mangle (Cat): CP
4492 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4494 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4495 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4498 // take ammo
4499 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4501 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4503 // wands don't have ammo
4504 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4505 return;
4507 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4509 if(pItem->GetMaxStackCount()==1)
4511 // decrease durability for non-stackable throw weapon
4512 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4514 else
4516 // decrease items amount for stackable throw weapon
4517 uint32 count = 1;
4518 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4521 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4522 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4526 void Spell::EffectThreat(uint32 /*i*/)
4528 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4529 return;
4531 if(!unitTarget->CanHaveThreatList())
4532 return;
4534 unitTarget->AddThreat(m_caster, float(damage));
4537 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4539 if(!unitTarget)
4540 return;
4541 if(!unitTarget->isAlive())
4542 return;
4544 uint32 heal = m_caster->GetMaxHealth();
4546 m_healing+=heal;
4549 void Spell::EffectInterruptCast(uint32 /*i*/)
4551 if(!unitTarget)
4552 return;
4553 if(!unitTarget->isAlive())
4554 return;
4556 // TODO: not all spells that used this effect apply cooldown at school spells
4557 // also exist case: apply cooldown to interrupted cast only and to all spells
4558 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4560 if (unitTarget->m_currentSpells[i])
4562 // check if we can interrupt spell
4563 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4565 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4566 unitTarget->InterruptSpell(i,false);
4572 void Spell::EffectSummonObjectWild(uint32 i)
4574 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4576 GameObject* pGameObj = new GameObject;
4578 WorldObject* target = focusObject;
4579 if( !target )
4580 target = m_caster;
4582 float x,y,z;
4583 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4585 x = m_targets.m_destX;
4586 y = m_targets.m_destY;
4587 z = m_targets.m_destZ;
4589 else
4590 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4592 Map *map = target->GetMap();
4594 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4595 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4597 delete pGameObj;
4598 return;
4601 int32 duration = GetSpellDuration(m_spellInfo);
4602 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4603 pGameObj->SetSpellId(m_spellInfo->Id);
4605 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4606 m_caster->AddGameObject(pGameObj);
4607 map->Add(pGameObj);
4609 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4611 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4613 Player *pl = (Player*)m_caster;
4614 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4615 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4617 uint32 team = ALLIANCE;
4619 if(pl->GetTeam() == team)
4620 team = HORDE;
4622 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4627 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4629 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4631 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4632 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4634 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4639 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4641 GameObject* linkedGO = new GameObject;
4642 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4643 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4645 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4646 linkedGO->SetSpellId(m_spellInfo->Id);
4648 m_caster->AddGameObject(linkedGO);
4649 map->Add(linkedGO);
4651 else
4653 delete linkedGO;
4654 linkedGO = NULL;
4655 return;
4660 void Spell::EffectScriptEffect(uint32 effIndex)
4662 // TODO: we must implement hunter pet summon at login there (spell 6962)
4664 switch(m_spellInfo->SpellFamilyName)
4666 case SPELLFAMILY_GENERIC:
4668 switch(m_spellInfo->Id)
4670 // PX-238 Winter Wondervolt TRAP
4671 case 26275:
4673 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4675 // check presence
4676 for(int j = 0; j < 4; ++j)
4677 if(unitTarget->HasAura(spells[j],0))
4678 return;
4680 // select spell
4681 uint32 iTmpSpellId = spells[urand(0,3)];
4683 // cast
4684 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4685 return;
4687 // Bending Shinbone
4688 case 8856:
4690 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4691 return;
4693 uint32 spell_id = 0;
4694 switch(urand(1,5))
4696 case 1: spell_id = 8854; break;
4697 default: spell_id = 8855; break;
4700 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4701 return;
4703 // Brittle Armor - need remove one 24575 Brittle Armor aura
4704 case 24590:
4705 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4706 return;
4707 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4708 case 26465:
4709 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4710 return;
4711 // Orb teleport spells
4712 case 25140:
4713 case 25143:
4714 case 25650:
4715 case 25652:
4716 case 29128:
4717 case 29129:
4718 case 35376:
4719 case 35727:
4721 if(!unitTarget)
4722 return;
4724 uint32 spellid;
4725 switch(m_spellInfo->Id)
4727 case 25140: spellid = 32571; break;
4728 case 25143: spellid = 32572; break;
4729 case 25650: spellid = 30140; break;
4730 case 25652: spellid = 30141; break;
4731 case 29128: spellid = 32568; break;
4732 case 29129: spellid = 32569; break;
4733 case 35376: spellid = 25649; break;
4734 case 35727: spellid = 35730; break;
4735 default:
4736 return;
4739 unitTarget->CastSpell(unitTarget,spellid,false);
4740 return;
4742 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4743 case 22539:
4744 case 22972:
4745 case 22975:
4746 case 22976:
4747 case 22977:
4748 case 22978:
4749 case 22979:
4750 case 22980:
4751 case 22981:
4752 case 22982:
4753 case 22983:
4754 case 22984:
4755 case 22985:
4757 if(!unitTarget || !unitTarget->isAlive())
4758 return;
4760 // Onyxia Scale Cloak
4761 if(unitTarget->GetDummyAura(22683))
4762 return;
4764 // Shadow Flame
4765 m_caster->CastSpell(unitTarget, 22682, true);
4766 return;
4768 // Summon Black Qiraji Battle Tank
4769 case 26656:
4771 if(!unitTarget)
4772 return;
4774 // Prevent stacking of mounts
4775 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4777 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4778 if (unitTarget->GetAreaId() == 3428)
4779 unitTarget->CastSpell(unitTarget, 25863, false);
4780 else
4781 unitTarget->CastSpell(unitTarget, 26655, false);
4782 break;
4784 // Piccolo of the Flaming Fire
4785 case 17512:
4787 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4788 return;
4789 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4790 break;
4792 // Mirren's Drinking Hat
4793 case 29830:
4795 uint32 item = 0;
4796 switch ( urand(1,6) )
4798 case 1:case 2:case 3:
4799 item = 23584;break; // Loch Modan Lager
4800 case 4:case 5:
4801 item = 23585;break; // Stouthammer Lite
4802 case 6:
4803 item = 23586;break; // Aerie Peak Pale Ale
4805 if (item)
4806 DoCreateItem(effIndex,item);
4807 break;
4809 // Improved Sprint
4810 case 30918:
4812 // Removes snares and roots.
4813 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4814 Unit::AuraMap& Auras = unitTarget->GetAuras();
4815 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4817 next = iter;
4818 ++next;
4819 Aura *aur = iter->second;
4820 if (!aur->IsPositive()) //only remove negative spells
4822 // check for mechanic mask
4823 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4825 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4826 if(Auras.empty())
4827 break;
4828 else
4829 next = Auras.begin();
4833 break;
4835 // Flame Crash
4836 case 41126:
4838 if(!unitTarget)
4839 return;
4841 unitTarget->CastSpell(unitTarget, 41131, true);
4842 break;
4844 // Force Cast - Portal Effect: Sunwell Isle
4845 case 44876:
4847 if(!unitTarget)
4848 return;
4850 unitTarget->CastSpell(unitTarget, 44870, true);
4851 break;
4853 // Goblin Weather Machine
4854 case 46203:
4856 if(!unitTarget)
4857 return;
4859 uint32 spellId;
4860 switch(rand()%4)
4862 case 0: spellId = 46740; break;
4863 case 1: spellId = 46739; break;
4864 case 2: spellId = 46738; break;
4865 case 3: spellId = 46736; break;
4867 unitTarget->CastSpell(unitTarget, spellId, true);
4868 break;
4870 //5,000 Gold
4871 case 46642:
4873 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4874 return;
4876 ((Player*)unitTarget)->ModifyMoney(50000000);
4878 break;
4880 // Emblazon Runeblade
4881 case 51770:
4883 if(!unitTarget)
4884 return;
4886 unitTarget->CastSpell(unitTarget,51771,false);
4887 break;
4889 // Death Gate
4890 case 52751:
4892 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4893 return;
4894 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4895 unitTarget->CastSpell(unitTarget, damage, false);
4896 break;
4898 // random spell learn instead placeholder
4899 case 60893: // Northrend Alchemy Research
4900 case 61177: // Northrend Inscription Research
4901 case 61288: // Minor Inscription Research
4902 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4904 if(!IsExplicitDiscoverySpell(m_spellInfo))
4906 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4907 return;
4910 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4911 return;
4912 Player* player = (Player*)m_caster;
4914 // need replace effect 0 item by loot
4915 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4917 if(!player->HasItemCount(reagent_id,1))
4918 return;
4920 // remove reagent
4921 uint32 count = 1;
4922 player->DestroyItemCount (reagent_id,count,true);
4924 // create some random items
4925 player->AutoStoreLootItem(m_spellInfo->Id,LootTemplates_Spell);
4927 // learn random explicit discovery recipe (if any)
4928 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4929 player->learnSpell(discoveredSpell,false);
4930 return;
4933 break;
4935 case SPELLFAMILY_WARLOCK:
4937 switch(m_spellInfo->Id)
4939 // Healthstone creating spells
4940 case 6201:
4941 case 6202:
4942 case 5699:
4943 case 11729:
4944 case 11730:
4945 case 27230:
4946 case 47871:
4947 case 47878:
4949 uint32 itemtype;
4950 uint32 rank = 0;
4951 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4952 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4954 if((*i)->GetId() == 18692)
4956 rank = 1;
4957 break;
4959 else if((*i)->GetId() == 18693)
4961 rank = 2;
4962 break;
4966 static uint32 const itypes[8][3] = {
4967 { 5512,19004,19005}, // Minor Healthstone
4968 { 5511,19006,19007}, // Lesser Healthstone
4969 { 5509,19008,19009}, // Healthstone
4970 { 5510,19010,19011}, // Greater Healthstone
4971 { 9421,19012,19013}, // Major Healthstone
4972 {22103,22104,22105}, // Master Healthstone
4973 {36889,36890,36891}, // Demonic Healthstone
4974 {36892,36893,36894} // Fel Healthstone
4977 switch(m_spellInfo->Id)
4979 case 6201:
4980 itemtype=itypes[0][rank];break; // Minor Healthstone
4981 case 6202:
4982 itemtype=itypes[1][rank];break; // Lesser Healthstone
4983 case 5699:
4984 itemtype=itypes[2][rank];break; // Healthstone
4985 case 11729:
4986 itemtype=itypes[3][rank];break; // Greater Healthstone
4987 case 11730:
4988 itemtype=itypes[4][rank];break; // Major Healthstone
4989 case 27230:
4990 itemtype=itypes[5][rank];break; // Master Healthstone
4991 case 47871:
4992 itemtype=itypes[6][rank];break; // Demonic Healthstone
4993 case 47878:
4994 itemtype=itypes[7][rank];break; // Fel Healthstone
4995 default:
4996 return;
4998 DoCreateItem( effIndex, itemtype );
4999 return;
5002 break;
5004 case SPELLFAMILY_PRIEST:
5006 switch(m_spellInfo->Id)
5008 // Pain and Suffering
5009 case 47948:
5011 if (!unitTarget)
5012 return;
5013 // Refresh Shadow Word: Pain on target
5014 Unit::AuraMap& auras = unitTarget->GetAuras();
5015 for(Unit::AuraMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
5017 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5018 if( spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST &&
5019 spellInfo->SpellFamilyFlags & 0x0000000000008000LL &&
5020 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
5022 (*itr).second->RefreshAura();
5023 return;
5026 return;
5028 default:
5029 break;
5031 break;
5033 case SPELLFAMILY_HUNTER:
5035 switch(m_spellInfo->Id)
5037 // Chimera Shot
5038 case 53209:
5040 uint32 spellId = 0;
5041 int32 basePoint = 0;
5042 Unit::AuraMap& Auras = unitTarget->GetAuras();
5043 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
5045 Aura *aura = (*i).second;
5046 if (aura->GetCasterGUID() != m_caster->GetGUID())
5047 continue;
5048 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
5049 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
5050 if (!(familyFlag & 0x000000800000C000LL))
5051 continue;
5052 // Refresh aura duration
5053 aura->RefreshAura();
5055 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
5056 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
5058 spellId = 53353; // 53353 Chimera Shot - Serpent
5059 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
5061 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
5062 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
5064 spellId = 53358; // 53358 Chimera Shot - Viper
5065 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
5067 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
5068 if (familyFlag & 0x0000000000008000LL)
5069 spellId = 53359; // 53359 Chimera Shot - Scorpid
5070 // ?? nothing say in spell desc (possibly need addition check)
5071 //if (familyFlag & 0x0000010000000000LL || // dot
5072 // familyFlag & 0x0000100000000000LL) // stun
5074 // spellId = 53366; // 53366 Chimera Shot - Wyvern
5077 if (spellId)
5078 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
5079 return;
5081 default:
5082 break;
5084 break;
5086 case SPELLFAMILY_PALADIN:
5088 // Judgement
5089 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5091 if(!unitTarget || !unitTarget->isAlive())
5092 return;
5093 uint32 spellId1 = 0;
5094 uint32 spellId2 = 0;
5096 // Judgement self add switch
5097 switch (m_spellInfo->Id)
5099 case 41467: break; // Judgement
5100 case 53407: spellId1 = 20184; break; // Judgement of Justice
5101 case 20271: // Judgement of Light
5102 case 57774: spellId1 = 20185; break; // Judgement of Light
5103 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5104 default:
5105 return;
5107 // all seals have aura dummy in 2 effect
5108 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5109 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5111 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5112 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5113 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5114 continue;
5115 spellId2 = (*itr)->GetModifier()->m_amount;
5116 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5117 if (!judge)
5118 continue;
5119 break;
5121 if (spellId1)
5122 m_caster->CastSpell(unitTarget, spellId1, true);
5123 if (spellId2)
5124 m_caster->CastSpell(unitTarget, spellId2, true);
5125 return;
5128 case SPELLFAMILY_POTION:
5130 switch(m_spellInfo->Id)
5132 // Dreaming Glory
5133 case 28698:
5135 if(!unitTarget)
5136 return;
5137 unitTarget->CastSpell(unitTarget, 28694, true);
5138 break;
5140 // Netherbloom
5141 case 28702:
5143 if(!unitTarget)
5144 return;
5145 // 25% chance of casting a random buff
5146 if(roll_chance_i(75))
5147 return;
5149 // triggered spells are 28703 to 28707
5150 // Note: some sources say, that there was the possibility of
5151 // receiving a debuff. However, this seems to be removed by a patch.
5152 const uint32 spellid = 28703;
5154 // don't overwrite an existing aura
5155 for(uint8 i=0; i<5; i++)
5156 if(unitTarget->HasAura(spellid+i, 0))
5157 return;
5158 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5159 break;
5162 // Nightmare Vine
5163 case 28720:
5165 if(!unitTarget)
5166 return;
5167 // 25% chance of casting Nightmare Pollen
5168 if(roll_chance_i(75))
5169 return;
5170 unitTarget->CastSpell(unitTarget, 28721, true);
5171 break;
5174 break;
5178 // normal DB scripted effect
5179 if(!unitTarget)
5180 return;
5182 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5183 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5186 void Spell::EffectSanctuary(uint32 /*i*/)
5188 if(!unitTarget)
5189 return;
5190 //unitTarget->CombatStop();
5192 unitTarget->CombatStop();
5193 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5194 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5195 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5197 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5201 void Spell::EffectAddComboPoints(uint32 /*i*/)
5203 if(!unitTarget)
5204 return;
5206 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5207 return;
5209 if(damage <= 0)
5210 return;
5212 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5215 void Spell::EffectDuel(uint32 i)
5217 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5218 return;
5220 Player *caster = (Player*)m_caster;
5221 Player *target = (Player*)unitTarget;
5223 // caster or target already have requested duel
5224 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5225 return;
5227 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5228 // Don't have to check the target's map since you cannot challenge someone across maps
5229 uint32 mapid = caster->GetMapId();
5230 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5232 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5233 return;
5236 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5237 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5239 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5240 return;
5243 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5244 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5246 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5247 return;
5250 //CREATE DUEL FLAG OBJECT
5251 GameObject* pGameObj = new GameObject;
5253 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5255 Map *map = m_caster->GetMap();
5256 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
5257 map, m_caster->GetPhaseMask(),
5258 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5259 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5260 m_caster->GetPositionZ(),
5261 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5263 delete pGameObj;
5264 return;
5267 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5268 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5269 int32 duration = GetSpellDuration(m_spellInfo);
5270 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5271 pGameObj->SetSpellId(m_spellInfo->Id);
5273 m_caster->AddGameObject(pGameObj);
5274 map->Add(pGameObj);
5275 //END
5277 // Send request
5278 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5279 data << pGameObj->GetGUID();
5280 data << caster->GetGUID();
5281 caster->GetSession()->SendPacket(&data);
5282 target->GetSession()->SendPacket(&data);
5284 // create duel-info
5285 DuelInfo *duel = new DuelInfo;
5286 duel->initiator = caster;
5287 duel->opponent = target;
5288 duel->startTime = 0;
5289 duel->startTimer = 0;
5290 caster->duel = duel;
5292 DuelInfo *duel2 = new DuelInfo;
5293 duel2->initiator = caster;
5294 duel2->opponent = caster;
5295 duel2->startTime = 0;
5296 duel2->startTimer = 0;
5297 target->duel = duel2;
5299 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5300 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5303 void Spell::EffectStuck(uint32 /*i*/)
5305 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5306 return;
5308 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5309 return;
5311 Player* pTarget = (Player*)unitTarget;
5313 sLog.outDebug("Spell Effect: Stuck");
5314 sLog.outDetail("Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", pTarget->GetName(), pTarget->GetGUIDLow(), m_caster->GetMapId(), m_caster->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ());
5316 if(pTarget->isInFlight())
5317 return;
5319 // homebind location is loaded always
5320 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5322 // Stuck spell trigger Hearthstone cooldown
5323 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5324 if(!spellInfo)
5325 return;
5326 Spell spell(pTarget,spellInfo,true,0);
5327 spell.SendSpellCooldown();
5330 void Spell::EffectSummonPlayer(uint32 /*i*/)
5332 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5333 return;
5335 // Evil Twin (ignore player summon, but hide this for summoner)
5336 if(unitTarget->GetDummyAura(23445))
5337 return;
5339 float x,y,z;
5340 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5342 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5344 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5345 data << uint64(m_caster->GetGUID()); // summoner guid
5346 data << uint32(m_caster->GetZoneId()); // summoner zone
5347 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5348 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5351 static ScriptInfo generateActivateCommand()
5353 ScriptInfo si;
5354 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5355 return si;
5358 void Spell::EffectActivateObject(uint32 effect_idx)
5360 if(!gameObjTarget)
5361 return;
5363 static ScriptInfo activateCommand = generateActivateCommand();
5365 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5367 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5370 void Spell::EffectApplyGlyph(uint32 i)
5372 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5373 return;
5375 Player *player = (Player*)m_caster;
5377 // remove old glyph
5378 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5380 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5382 player->RemoveAurasDueToSpell(old_gp->SpellId);
5383 player->SetGlyph(m_glyphIndex, 0);
5387 // apply new one
5388 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5390 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5392 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5394 if(gp->TypeFlags != gs->TypeFlags)
5396 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5397 return; // glyph slot missmatch
5401 player->CastSpell(m_caster, gp->SpellId, true);
5402 player->SetGlyph(m_glyphIndex, glyph);
5407 void Spell::EffectSummonTotem(uint32 i)
5409 uint8 slot = 0;
5410 switch(m_spellInfo->EffectMiscValueB[i])
5412 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5413 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5414 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5415 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5416 // Battle standard case
5417 case SUMMON_TYPE_TOTEM: slot = 254; break;
5418 // jewelery statue case, like totem without slot
5419 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5420 default: return;
5423 if(slot < MAX_TOTEM)
5425 uint64 guid = m_caster->m_TotemSlot[slot];
5426 if(guid != 0)
5428 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5429 if(OldTotem && OldTotem->isTotem())
5430 ((Totem*)OldTotem)->UnSummon();
5434 uint32 team = 0;
5435 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5436 team = ((Player*)m_caster)->GetTeam();
5438 Totem* pTotem = new Totem;
5440 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
5441 m_spellInfo->EffectMiscValue[i], team ))
5443 delete pTotem;
5444 return;
5447 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5449 float x,y,z;
5450 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5452 // totem must be at same Z in case swimming caster and etc.
5453 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5454 z = m_caster->GetPositionZ();
5456 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5458 if(slot < MAX_TOTEM)
5459 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5461 pTotem->SetOwner(m_caster->GetGUID());
5462 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5464 int32 duration=GetSpellDuration(m_spellInfo);
5465 if(Player* modOwner = m_caster->GetSpellModOwner())
5466 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5467 pTotem->SetDuration(duration);
5469 if (damage) // if not spell info, DB values used
5471 pTotem->SetMaxHealth(damage);
5472 pTotem->SetHealth(damage);
5475 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5477 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5478 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5480 pTotem->Summon(m_caster);
5482 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5484 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5485 data << uint8(slot);
5486 data << uint64(pTotem->GetGUID());
5487 data << uint32(duration);
5488 data << uint32(m_spellInfo->Id);
5489 ((Player*)m_caster)->SendDirectMessage(&data);
5493 void Spell::EffectEnchantHeldItem(uint32 i)
5495 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5496 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5497 return;
5499 Player* item_owner = (Player*)unitTarget;
5500 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5502 if(!item )
5503 return;
5505 // must be equipped
5506 if(!item ->IsEquipped())
5507 return;
5509 if (m_spellInfo->EffectMiscValue[i])
5511 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5512 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5513 if(!duration)
5514 duration = m_currentBasePoints[i]+1; //Base points after ..
5515 if(!duration)
5516 duration = 10; //10 seconds for enchants which don't have listed duration
5518 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5519 if(!pEnchant)
5520 return;
5522 // Always go to temp enchantment slot
5523 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5525 // Enchantment will not be applied if a different one already exists
5526 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5527 return;
5529 // Apply the temporary enchantment
5530 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5531 item_owner->ApplyEnchantment(item,slot,true);
5535 void Spell::EffectDisEnchant(uint32 /*i*/)
5537 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5538 return;
5540 Player* p_caster = (Player*)m_caster;
5541 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5542 return;
5544 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5546 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5548 // item will be removed at disenchanting end
5551 void Spell::EffectInebriate(uint32 /*i*/)
5553 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5554 return;
5556 Player *player = (Player*)unitTarget;
5557 uint16 currentDrunk = player->GetDrunkValue();
5558 uint16 drunkMod = damage * 256;
5559 if (currentDrunk + drunkMod > 0xFFFF)
5560 currentDrunk = 0xFFFF;
5561 else
5562 currentDrunk += drunkMod;
5563 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5566 void Spell::EffectFeedPet(uint32 i)
5568 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5569 return;
5571 Player *_player = (Player*)m_caster;
5573 Item* foodItem = m_targets.getItemTarget();
5574 if(!foodItem)
5575 return;
5577 Pet *pet = _player->GetPet();
5578 if(!pet)
5579 return;
5581 if(!pet->isAlive())
5582 return;
5584 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5585 if(benefit <= 0)
5586 return;
5588 uint32 count = 1;
5589 _player->DestroyItemCount(foodItem,count,true);
5590 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5592 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5595 void Spell::EffectDismissPet(uint32 /*i*/)
5597 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5598 return;
5600 Pet* pet = m_caster->GetPet();
5602 // not let dismiss dead pet
5603 if(!pet||!pet->isAlive())
5604 return;
5606 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5609 void Spell::EffectSummonObject(uint32 i)
5611 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5613 uint8 slot = 0;
5614 switch(m_spellInfo->Effect[i])
5616 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5617 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5618 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5619 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5620 default: return;
5623 uint64 guid = m_caster->m_ObjectSlot[slot];
5624 if(guid != 0)
5626 GameObject* obj = NULL;
5627 if( m_caster )
5628 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5630 if(obj) obj->Delete();
5631 m_caster->m_ObjectSlot[slot] = 0;
5634 GameObject* pGameObj = new GameObject;
5636 float rot2 = sin(m_caster->GetOrientation()/2);
5637 float rot3 = cos(m_caster->GetOrientation()/2);
5639 float x,y,z;
5640 // If dest location if present
5641 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5643 x = m_targets.m_destX;
5644 y = m_targets.m_destY;
5645 z = m_targets.m_destZ;
5647 // Summon in random point all other units if location present
5648 else
5649 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5651 Map *map = m_caster->GetMap();
5652 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
5653 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5655 delete pGameObj;
5656 return;
5659 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5660 int32 duration = GetSpellDuration(m_spellInfo);
5661 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5662 pGameObj->SetSpellId(m_spellInfo->Id);
5663 m_caster->AddGameObject(pGameObj);
5665 map->Add(pGameObj);
5666 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5667 data << pGameObj->GetGUID();
5668 m_caster->SendMessageToSet(&data,true);
5670 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5673 void Spell::EffectResurrect(uint32 /*effIndex*/)
5675 if(!unitTarget)
5676 return;
5677 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5678 return;
5680 if(unitTarget->isAlive())
5681 return;
5682 if(!unitTarget->IsInWorld())
5683 return;
5685 switch (m_spellInfo->Id)
5687 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5688 case 8342:
5689 if (roll_chance_i(67))
5691 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5692 return;
5694 break;
5695 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5696 case 22999:
5697 if (roll_chance_i(50))
5699 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5700 return;
5702 break;
5703 default:
5704 break;
5707 Player* pTarget = ((Player*)unitTarget);
5709 if(pTarget->isRessurectRequested()) // already have one active request
5710 return;
5712 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5713 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5715 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5716 SendResurrectRequest(pTarget);
5719 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5721 if(!unitTarget || !unitTarget->isAlive())
5722 return;
5724 if( unitTarget->m_extraAttacks )
5725 return;
5727 unitTarget->m_extraAttacks = damage;
5730 void Spell::EffectParry(uint32 /*i*/)
5732 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5733 ((Player*)unitTarget)->SetCanParry(true);
5736 void Spell::EffectBlock(uint32 /*i*/)
5738 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5739 ((Player*)unitTarget)->SetCanBlock(true);
5742 void Spell::EffectMomentMove(uint32 i)
5744 if(unitTarget->isInFlight())
5745 return;
5747 if( m_spellInfo->rangeIndex== 1) //self range
5749 uint32 mapid = m_caster->GetMapId();
5750 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5752 // before caster
5753 float fx,fy,fz;
5754 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5755 float ox,oy,oz;
5756 unitTarget->GetPosition(ox,oy,oz);
5758 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5759 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5761 fx = fx2;
5762 fy = fy2;
5763 fz = fz2;
5764 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5767 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5768 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5769 else
5770 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5774 void Spell::EffectReputation(uint32 i)
5776 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5777 return;
5779 Player *_player = (Player*)unitTarget;
5781 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5783 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5785 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5787 if(!factionEntry)
5788 return;
5790 _player->ModifyFactionReputation(factionEntry,rep_change);
5793 void Spell::EffectQuestComplete(uint32 i)
5795 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5796 return;
5798 Player *_player = (Player*)m_caster;
5800 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5801 _player->AreaExploredOrEventHappens(quest_id);
5804 void Spell::EffectSelfResurrect(uint32 i)
5806 if(!unitTarget || unitTarget->isAlive())
5807 return;
5808 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5809 return;
5810 if(!unitTarget->IsInWorld())
5811 return;
5813 uint32 health = 0;
5814 uint32 mana = 0;
5816 // flat case
5817 if(damage < 0)
5819 health = uint32(-damage);
5820 mana = m_spellInfo->EffectMiscValue[i];
5822 // percent case
5823 else
5825 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5826 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5827 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5830 Player *plr = ((Player*)unitTarget);
5831 plr->ResurrectPlayer(0.0f);
5833 plr->SetHealth( health );
5834 plr->SetPower(POWER_MANA, mana );
5835 plr->SetPower(POWER_RAGE, 0 );
5836 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5838 plr->SpawnCorpseBones();
5840 plr->SaveToDB();
5843 void Spell::EffectSkinning(uint32 /*i*/)
5845 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5846 return;
5847 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5848 return;
5850 Creature* creature = (Creature*) unitTarget;
5851 int32 targetLevel = creature->getLevel();
5853 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5855 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5856 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5858 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5860 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5862 // Double chances for elites
5863 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5866 void Spell::EffectCharge(uint32 /*i*/)
5868 if(!unitTarget || !m_caster)
5869 return;
5871 float x, y, z;
5872 unitTarget->GetContactPoint(m_caster, x, y, z);
5873 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5874 ((Creature *)unitTarget)->StopMoving();
5876 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5877 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5879 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5880 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5882 // not all charge effects used in negative spells
5883 if ( !IsPositiveSpell(m_spellInfo->Id))
5884 m_caster->Attack(unitTarget,true);
5887 void Spell::EffectSummonCritter(uint32 i)
5889 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5890 return;
5891 Player* player = (Player*)m_caster;
5893 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5894 if(!pet_entry)
5895 return;
5897 Pet* old_critter = player->GetMiniPet();
5899 // for same pet just despawn
5900 if(old_critter && old_critter->GetEntry() == pet_entry)
5902 player->RemoveMiniPet();
5903 return;
5906 // despawn old pet before summon new
5907 if(old_critter)
5908 player->RemoveMiniPet();
5910 // summon new pet
5911 Pet* critter = new Pet(MINI_PET);
5913 Map *map = m_caster->GetMap();
5914 uint32 pet_number = objmgr.GeneratePetNumber();
5915 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
5916 pet_entry, pet_number))
5918 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5919 delete critter;
5920 return;
5923 float x,y,z;
5924 // If dest location if present
5925 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5927 x = m_targets.m_destX;
5928 y = m_targets.m_destY;
5929 z = m_targets.m_destZ;
5931 // Summon if dest location not present near caster
5932 else
5933 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5935 critter->Relocate(x,y,z,m_caster->GetOrientation());
5937 if(!critter->IsPositionValid())
5939 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5940 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5941 delete critter;
5942 return;
5945 critter->SetOwnerGUID(m_caster->GetGUID());
5946 critter->SetCreatorGUID(m_caster->GetGUID());
5947 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5948 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5950 critter->AIM_Initialize();
5951 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5952 critter->SetMaxHealth(1);
5953 critter->SetHealth(1);
5954 critter->SetLevel(1);
5956 // set timer for unsummon
5957 int32 duration = GetSpellDuration(m_spellInfo);
5958 if(duration > 0)
5959 critter->SetDuration(duration);
5961 std::string name = player->GetName();
5962 name.append(petTypeSuffix[critter->getPetType()]);
5963 critter->SetName( name );
5964 player->SetMiniPet(critter);
5966 map->Add((Creature*)critter);
5969 void Spell::EffectKnockBack(uint32 i)
5971 if(!unitTarget || !m_caster)
5972 return;
5974 // Effect only works on players
5975 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5976 return;
5978 float vsin = sin(m_caster->GetAngle(unitTarget));
5979 float vcos = cos(m_caster->GetAngle(unitTarget));
5981 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5982 data.append(unitTarget->GetPackGUID());
5983 data << uint32(0); // Sequence
5984 data << float(vcos); // x direction
5985 data << float(vsin); // y direction
5986 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5987 data << float(damage/-10); // Z Movement speed (vertical)
5989 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5992 void Spell::EffectSendTaxi(uint32 i)
5994 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5995 return;
5997 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5998 if(!entry)
5999 return;
6001 std::vector<uint32> nodes;
6003 nodes.resize(2);
6004 nodes[0] = entry->from;
6005 nodes[1] = entry->to;
6007 uint32 mountid = 0;
6008 switch(m_spellInfo->Id)
6010 case 31606: //Stormcrow Amulet
6011 mountid = 17447;
6012 break;
6013 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
6014 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
6015 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
6016 mountid = 22840;
6017 break;
6018 case 34905: //Stealth Flight
6019 mountid = 6851;
6020 break;
6021 case 45883: //Amber Ledge to Beryl Point
6022 mountid = 23524;
6023 break;
6024 case 46064: //Amber Ledge to Coldarra
6025 mountid = 6371;
6026 break;
6027 case 53335: //Stormwind Harbor Flight - Peaceful
6028 mountid = 6852;
6029 break;
6032 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
6036 void Spell::EffectPlayerPull(uint32 i)
6038 if(!unitTarget || !m_caster)
6039 return;
6041 // Effect only works on players
6042 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6043 return;
6045 float vsin = sin(unitTarget->GetAngle(m_caster));
6046 float vcos = cos(unitTarget->GetAngle(m_caster));
6048 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6049 data.append(unitTarget->GetPackGUID());
6050 data << uint32(0); // Sequence
6051 data << float(vcos); // x direction
6052 data << float(vsin); // y direction
6053 // Horizontal speed
6054 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
6055 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
6057 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6060 void Spell::EffectDispelMechanic(uint32 i)
6062 if(!unitTarget)
6063 return;
6065 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
6067 Unit::AuraMap& Auras = unitTarget->GetAuras();
6068 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
6070 next = iter;
6071 ++next;
6072 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
6073 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
6075 unitTarget->RemoveAurasDueToSpell(spell->Id);
6076 if(Auras.empty())
6077 break;
6078 else
6079 next = Auras.begin();
6082 return;
6085 void Spell::EffectSummonDeadPet(uint32 /*i*/)
6087 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6088 return;
6089 Player *_player = (Player*)m_caster;
6090 Pet *pet = _player->GetPet();
6091 if(!pet)
6092 return;
6093 if(pet->isAlive())
6094 return;
6095 if(damage < 0)
6096 return;
6097 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6098 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6099 pet->setDeathState( ALIVE );
6100 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6101 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6103 pet->AIM_Initialize();
6105 _player->PetSpellInitialize();
6106 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6109 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6111 float mana = 0;
6112 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6114 if(!m_caster->m_TotemSlot[slot])
6115 continue;
6117 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
6118 if(totem && totem->isTotem())
6120 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6121 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6122 if(spellInfo)
6123 mana += spellInfo->manaCost * damage / 100;
6124 ((Totem*)totem)->UnSummon();
6128 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
6129 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
6132 void Spell::EffectDurabilityDamage(uint32 i)
6134 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6135 return;
6137 int32 slot = m_spellInfo->EffectMiscValue[i];
6139 // FIXME: some spells effects have value -1/-2
6140 // Possibly its mean -1 all player equipped items and -2 all items
6141 if(slot < 0)
6143 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6144 return;
6147 // invalid slot value
6148 if(slot >= INVENTORY_SLOT_BAG_END)
6149 return;
6151 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6152 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6155 void Spell::EffectDurabilityDamagePCT(uint32 i)
6157 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6158 return;
6160 int32 slot = m_spellInfo->EffectMiscValue[i];
6162 // FIXME: some spells effects have value -1/-2
6163 // Possibly its mean -1 all player equipped items and -2 all items
6164 if(slot < 0)
6166 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6167 return;
6170 // invalid slot value
6171 if(slot >= INVENTORY_SLOT_BAG_END)
6172 return;
6174 if(damage <= 0)
6175 return;
6177 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6178 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6181 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6183 if(!unitTarget)
6184 return;
6186 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6189 void Spell::EffectTransmitted(uint32 effIndex)
6191 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6193 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6195 if (!goinfo)
6197 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6198 return;
6201 float fx,fy,fz;
6203 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6205 fx = m_targets.m_destX;
6206 fy = m_targets.m_destY;
6207 fz = m_targets.m_destZ;
6209 //FIXME: this can be better check for most objects but still hack
6210 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6212 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6213 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6215 else
6217 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6218 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6219 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6221 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6224 Map *cMap = m_caster->GetMap();
6226 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6228 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6229 { // but this is not proper, we really need to ignore not materialized objects
6230 SendCastResult(SPELL_FAILED_NOT_HERE);
6231 SendChannelUpdate(0);
6232 return;
6235 // replace by water level in this case
6236 fz = cMap->GetWaterLevel(fx,fy);
6238 // if gameobject is summoning object, it should be spawned right on caster's position
6239 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6241 m_caster->GetPosition(fx,fy,fz);
6244 GameObject* pGameObj = new GameObject;
6246 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6247 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6249 delete pGameObj;
6250 return;
6253 int32 duration = GetSpellDuration(m_spellInfo);
6255 switch(goinfo->type)
6257 case GAMEOBJECT_TYPE_FISHINGNODE:
6259 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6260 // Orientation3
6261 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6262 // Orientation4
6263 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6264 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6266 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6267 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6268 int32 lastSec;
6269 switch(urand(0, 3))
6271 case 0: lastSec = 3; break;
6272 case 1: lastSec = 7; break;
6273 case 2: lastSec = 13; break;
6274 case 3: lastSec = 17; break;
6277 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6278 break;
6280 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6282 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6284 pGameObj->AddUniqueUse((Player*)m_caster);
6285 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6287 break;
6289 case GAMEOBJECT_TYPE_FISHINGHOLE:
6290 case GAMEOBJECT_TYPE_CHEST:
6291 default:
6293 break;
6297 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6299 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6301 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6302 pGameObj->SetSpellId(m_spellInfo->Id);
6304 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6305 //m_caster->AddGameObject(pGameObj);
6306 //m_ObjToDel.push_back(pGameObj);
6308 cMap->Add(pGameObj);
6310 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6311 data << uint64(pGameObj->GetGUID());
6312 m_caster->SendMessageToSet(&data,true);
6314 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6316 GameObject* linkedGO = new GameObject;
6317 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6318 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6320 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6321 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6322 linkedGO->SetSpellId(m_spellInfo->Id);
6323 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6325 linkedGO->GetMap()->Add(linkedGO);
6327 else
6329 delete linkedGO;
6330 linkedGO = NULL;
6331 return;
6336 void Spell::EffectProspecting(uint32 /*i*/)
6338 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6339 return;
6341 Player* p_caster = (Player*)m_caster;
6342 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6343 return;
6345 if(itemTarget->GetCount() < 5)
6346 return;
6348 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6350 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6351 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6352 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6355 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6358 void Spell::EffectMilling(uint32 /*i*/)
6360 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6361 return;
6363 Player* p_caster = (Player*)m_caster;
6364 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6365 return;
6367 if(itemTarget->GetCount() < 5)
6368 return;
6370 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6372 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6373 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6374 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6377 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6380 void Spell::EffectSkill(uint32 /*i*/)
6382 sLog.outDebug("WORLD: SkillEFFECT");
6385 void Spell::EffectSummonDemon(uint32 i)
6387 float px = m_targets.m_destX;
6388 float py = m_targets.m_destY;
6389 float pz = m_targets.m_destZ;
6391 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6392 if (!Charmed)
6393 return;
6395 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6396 Charmed->SetLevel(m_caster->getLevel());
6398 // TODO: Add damage/mana/hp according to level
6400 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6402 // Enslave demon effect, without mana cost and cooldown
6403 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6405 // Inferno effect
6406 Charmed->CastSpell(Charmed, 22703, true, 0);
6410 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6411 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6412 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6413 This is why we use a half sec delay between the visual effect and the resurrection itself */
6414 void Spell::EffectSpiritHeal(uint32 /*i*/)
6417 if(!unitTarget || unitTarget->isAlive())
6418 return;
6419 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6420 return;
6421 if(!unitTarget->IsInWorld())
6422 return;
6424 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6425 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6426 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6427 ((Player*)unitTarget)->SpawnCorpseBones();
6431 // remove insignia spell effect
6432 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6434 sLog.outDebug("Effect: SkinPlayerCorpse");
6435 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6436 return;
6438 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6441 void Spell::EffectStealBeneficialBuff(uint32 i)
6443 sLog.outDebug("Effect: StealBeneficialBuff");
6445 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6446 return;
6448 std::vector <Aura *> steal_list;
6449 // Create dispel mask by dispel type
6450 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6451 Unit::AuraMap const& auras = unitTarget->GetAuras();
6452 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6454 Aura *aur = (*itr).second;
6455 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6457 // Need check for passive? this
6458 if (aur->IsPositive() && !aur->IsPassive())
6459 steal_list.push_back(aur);
6462 // Ok if exist some buffs for dispel try dispel it
6463 if (!steal_list.empty())
6465 std::list < std::pair<uint32,uint64> > success_list;
6466 int32 list_size = steal_list.size();
6467 // Dispell N = damage buffs (or while exist buffs for dispel)
6468 for (int32 count=0; count < damage && list_size > 0; ++count)
6470 // Random select buff for dispel
6471 Aura *aur = steal_list[urand(0, list_size-1)];
6472 // Not use chance for steal
6473 // TODO possible need do it
6474 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6476 // Remove buff from list for prevent doubles
6477 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6479 Aura *stealed = *j;
6480 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6482 j = steal_list.erase(j);
6483 --list_size;
6485 else
6486 ++j;
6489 // Really try steal and send log
6490 if (!success_list.empty())
6492 int32 count = success_list.size();
6493 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6494 data.append(unitTarget->GetPackGUID()); // Victim GUID
6495 data.append(m_caster->GetPackGUID()); // Caster GUID
6496 data << uint32(m_spellInfo->Id); // Dispell spell id
6497 data << uint8(0); // not used
6498 data << uint32(count); // count
6499 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6501 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6502 data << uint32(spellInfo->Id); // Spell Id
6503 data << uint8(0); // 0 - steals !=0 transfers
6504 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6506 m_caster->SendMessageToSet(&data, true);
6511 void Spell::EffectKillCredit(uint32 i)
6513 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6514 return;
6516 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6519 void Spell::EffectQuestFail(uint32 i)
6521 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6522 return;
6524 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6527 void Spell::EffectActivateRune(uint32 eff_idx)
6529 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6530 return;
6532 Player *plr = (Player*)m_caster;
6534 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6535 return;
6537 for(uint32 j = 0; j < MAX_RUNES; ++j)
6539 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6541 plr->SetRuneCooldown(j, 0);
6546 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6548 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6549 ((Player*)unitTarget)->SetCanTitanGrip(true);
6552 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6554 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6555 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6556 return;
6558 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);