[7146] Trailing whitespace code cleanup
[getmangos.git] / src / game / SpellEffects.cpp
blob6ee0f7d424e3db38ce6d0663af9597065341b086
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::EffectNULL, //156 Add Socket
218 &Spell::EffectCreateItem, //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 // Starfire
439 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
441 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
442 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
444 // Starfire Bonus (caster)
445 switch((*i)->GetModifier()->m_miscvalue)
447 case 5481: // Nordrassil Regalia - bonus
449 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
450 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
452 // Moonfire or Insect Swarm (target debuff from any casters)
453 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
455 int32 mod = (*i)->GetModifier()->m_amount;
456 damage += damage*mod/100;
457 break;
460 break;
462 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
464 damage += (*i)->GetModifier()->m_amount;
465 break;
470 //Mangle Bonus for the initial damage of Lacerate and Rake
471 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
472 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
474 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
475 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
476 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
478 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
479 break;
482 break;
484 case SPELLFAMILY_ROGUE:
486 // Envenom
487 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
489 // consume from stack dozes not more that have combo-points
490 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
492 Aura *poison = 0;
493 // Lookup for Deadly poison (only attacker applied)
494 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
495 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
496 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
497 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
498 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
500 poison = *itr;
501 break;
503 // count consumed deadly poison doses at target
504 if (poison)
506 uint32 spellId = poison->GetId();
507 uint32 doses = poison->GetStackAmount();
508 if (doses > combo)
509 doses = combo;
510 for (int i=0; i< doses; i++)
511 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
512 damage *= doses;
513 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
515 // Eviscerate and Envenom Bonus Damage (item set effect)
516 if(m_caster->GetDummyAura(37169))
517 damage += ((Player*)m_caster)->GetComboPoints()*40;
520 // Eviscerate
521 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
523 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
525 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
526 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
528 // Eviscerate and Envenom Bonus Damage (item set effect)
529 if(m_caster->GetDummyAura(37169))
530 damage += combo*40;
533 // Gouge
534 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
536 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.02f);
538 // Instant Poison
539 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
541 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
543 // Wound Poison
544 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
546 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
548 break;
550 case SPELLFAMILY_HUNTER:
552 // Mongoose Bite
553 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
555 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
557 // Counterattack
558 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
560 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
562 // Arcane Shot
563 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
565 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
567 // Steady Shot
568 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
570 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
571 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
573 // Explosive Trap Effect
574 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
576 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
578 break;
580 case SPELLFAMILY_PALADIN:
582 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
583 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
585 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
586 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
587 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
588 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
589 // Get stack of Holy Vengeance on the target added by caster
590 uint32 stacks = 0;
591 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
592 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
593 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
595 stacks = (*itr)->GetStackAmount();
596 break;
598 // + 10% for each application of Holy Vengeance on the target
599 if(stacks)
600 damage += damage * stacks * 10 /100;
602 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
603 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
605 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
606 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
607 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
608 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
610 // Exorcism ($m1+0.15*$SPH+0.15*$AP)
611 else if(m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
613 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
614 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
615 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
616 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
618 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP)
619 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
621 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
622 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
623 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
624 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
626 // Holy Wrath ($m1+0.07*$SPH+0.07*$AP)
627 else if(m_spellInfo->SpellFamilyFlags & 0x0020000000000000LL)
629 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
630 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
631 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
632 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
634 break;
638 if(damage >= 0)
639 m_damage+= damage;
643 void Spell::EffectDummy(uint32 i)
645 if(!unitTarget && !gameObjTarget && !itemTarget)
646 return;
648 // selection by spell family
649 switch(m_spellInfo->SpellFamilyName)
651 case SPELLFAMILY_GENERIC:
653 switch(m_spellInfo->Id )
655 case 8063: // Deviate Fish
657 if(m_caster->GetTypeId() != TYPEID_PLAYER)
658 return;
660 uint32 spell_id = 0;
661 switch(urand(1,5))
663 case 1: spell_id = 8064; break; // Sleepy
664 case 2: spell_id = 8065; break; // Invigorate
665 case 3: spell_id = 8066; break; // Shrink
666 case 4: spell_id = 8067; break; // Party Time!
667 case 5: spell_id = 8068; break; // Healthy Spirit
669 m_caster->CastSpell(m_caster,spell_id,true,NULL);
670 return;
672 case 8213: // Savory Deviate Delight
674 if(m_caster->GetTypeId() != TYPEID_PLAYER)
675 return;
677 uint32 spell_id = 0;
678 switch(urand(1,2))
680 // Flip Out - ninja
681 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
682 // Yaaarrrr - pirate
683 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
685 m_caster->CastSpell(m_caster,spell_id,true,NULL);
686 return;
688 case 8593: // Symbol of life (restore creature to life)
689 case 31225: // Shimmering Vessel (restore creature to life)
691 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
692 return;
693 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
694 return;
696 case 12162: // Deep wounds
697 case 12850: // (now good common check for this spells)
698 case 12868:
700 if(!unitTarget)
701 return;
703 float damage;
704 // DW should benefit of attack power, damage percent mods etc.
705 // TODO: check if using offhand damage is correct and if it should be divided by 2
706 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
707 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
708 else
709 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
711 switch (m_spellInfo->Id)
713 case 12850: damage *= 0.2f; break;
714 case 12162: damage *= 0.4f; break;
715 case 12868: damage *= 0.6f; break;
716 default:
717 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
718 return;
721 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
722 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
723 return;
725 case 13120: // net-o-matic
727 if(!unitTarget)
728 return;
730 uint32 spell_id = 0;
732 uint32 roll = urand(0, 99);
734 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
735 spell_id = 16566;
736 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
737 spell_id = 13119;
738 else // normal root
739 spell_id = 13099;
741 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
742 return;
744 case 13567: // Dummy Trigger
746 // can be used for different aura triggering, so select by aura
747 if(!m_triggeredByAuraSpell || !unitTarget)
748 return;
750 switch(m_triggeredByAuraSpell->Id)
752 case 26467: // Persistent Shield
753 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
754 break;
755 default:
756 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
757 break;
759 return;
761 case 15998: // Capture Worg Pup
762 case 29435: // Capture Female Kaliri Hatchling
764 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
765 return;
767 Creature* creatureTarget = (Creature*)unitTarget;
768 creatureTarget->setDeathState(JUST_DIED);
769 creatureTarget->RemoveCorpse();
770 creatureTarget->SetHealth(0); // just for nice GM-mode view
771 return;
773 case 16589: // Noggenfogger Elixir
775 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
776 return;
778 uint32 spell_id = 0;
779 switch(urand(1,3))
781 case 1: spell_id = 16595; break;
782 case 2: spell_id = 16593; break;
783 default:spell_id = 16591; break;
786 m_caster->CastSpell(m_caster,spell_id,true,NULL);
787 return;
789 case 17251: // Spirit Healer Res
791 if(!unitTarget || !m_originalCaster)
792 return;
794 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
796 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
797 data << unitTarget->GetGUID();
798 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
800 return;
802 case 17271: // Test Fetid Skull
804 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
805 return;
807 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
809 m_caster->CastSpell(m_caster,spell_id,true,NULL);
810 return;
812 case 20577: // Cannibalize
813 if (unitTarget)
814 m_caster->CastSpell(m_caster,20578,false,NULL);
815 return;
816 case 23019: // Crystal Prison Dummy DND
818 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
819 return;
821 Creature* creatureTarget = (Creature*)unitTarget;
822 if(creatureTarget->isPet())
823 return;
825 creatureTarget->setDeathState(JUST_DIED);
826 creatureTarget->RemoveCorpse();
827 creatureTarget->SetHealth(0); // just for nice GM-mode view
829 GameObject* pGameObj = new GameObject;
831 Map *map = creatureTarget->GetMap();
833 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
834 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
835 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
837 delete pGameObj;
838 return;
841 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
842 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
843 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
844 pGameObj->SetSpellId(m_spellInfo->Id);
846 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
847 map->Add(pGameObj);
849 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
850 data << uint64(pGameObj->GetGUID());
851 m_caster->SendMessageToSet(&data,true);
853 return;
855 case 23074: // Arcanite Dragonling
856 if (!m_CastItem) return;
857 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
858 return;
859 case 23075: // Mithril Mechanical Dragonling
860 if (!m_CastItem) return;
861 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
862 return;
863 case 23076: // Mechanical Dragonling
864 if (!m_CastItem) return;
865 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
866 return;
867 case 23133: // Gnomish Battle Chicken
868 if (!m_CastItem) return;
869 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
870 return;
871 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
873 int32 r = irand(0, 119);
874 if ( r < 20 ) // 1/6 polymorph
875 m_caster->CastSpell(m_caster,23444,true);
876 else if ( r < 100 ) // 4/6 evil twin
877 m_caster->CastSpell(m_caster,23445,true);
878 else // 1/6 miss the target
879 m_caster->CastSpell(m_caster,36902,true);
880 return;
882 case 23453: // Ultrasafe Transporter: Gadgetzan
883 if ( roll_chance_i(50) ) // success
884 m_caster->CastSpell(m_caster,23441,true);
885 else // failure
886 m_caster->CastSpell(m_caster,23446,true);
887 return;
888 case 23645: // Hourglass Sand
889 m_caster->RemoveAurasDueToSpell(23170);
890 return;
891 case 23725: // Gift of Life (warrior bwl trinket)
892 m_caster->CastSpell(m_caster,23782,true);
893 m_caster->CastSpell(m_caster,23783,true);
894 return;
895 case 25860: // Reindeer Transformation
897 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
898 return;
900 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
901 float speed = m_caster->GetSpeedRate(MOVE_RUN);
903 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
905 //5 different spells used depending on mounted speed and if mount can fly or not
906 if (flyspeed >= 4.1f)
907 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
908 else if (flyspeed >= 3.8f)
909 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
910 else if (flyspeed >= 1.6f)
911 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
912 else if (speed >= 2.0f)
913 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
914 else
915 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
917 return;
919 //case 26074: // Holiday Cheer
920 // return; -- implemented at client side
921 case 28006: // Arcane Cloaking
923 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
924 m_caster->CastSpell(unitTarget,29294,true);
925 return;
927 case 28730: // Arcane Torrent (Mana)
929 Aura * dummy = m_caster->GetDummyAura(28734);
930 if (dummy)
932 int32 bp = damage * dummy->GetStackAmount();
933 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
934 m_caster->RemoveAurasDueToSpell(28734);
936 return;
938 case 29200: // Purify Helboar Meat
940 if( m_caster->GetTypeId() != TYPEID_PLAYER )
941 return;
943 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
945 m_caster->CastSpell(m_caster,spell_id,true,NULL);
946 return;
948 case 29858: // Soulshatter
949 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
950 m_caster->CastSpell(unitTarget,32835,true);
951 return;
952 case 30458: // Nigh Invulnerability
953 if (!m_CastItem) return;
954 if(roll_chance_i(86)) // success
955 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
956 else // backfire in 14% casts
957 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
958 return;
959 case 30507: // Poultryizer
960 if (!m_CastItem) return;
961 if(roll_chance_i(80)) // success
962 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
963 else // backfire 20%
964 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
965 return;
966 case 33060: // Make a Wish
968 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
969 return;
971 uint32 spell_id = 0;
973 switch(urand(1,5))
975 case 1: spell_id = 33053; break;
976 case 2: spell_id = 33057; break;
977 case 3: spell_id = 33059; break;
978 case 4: spell_id = 33062; break;
979 case 5: spell_id = 33064; break;
982 m_caster->CastSpell(m_caster,spell_id,true,NULL);
983 return;
985 case 35745:
987 uint32 spell_id;
988 switch(m_caster->GetAreaId())
990 case 3900: spell_id = 35743; break;
991 case 3742: spell_id = 35744; break;
992 default: return;
995 m_caster->CastSpell(m_caster,spell_id,true);
996 return;
998 case 37674: // Chaos Blast
1000 if(!unitTarget)
1001 return;
1003 int32 basepoints0 = 100;
1004 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
1005 return;
1007 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
1009 // selecting one from Bloodstained Fortune item
1010 uint32 newitemid;
1011 switch(urand(1,20))
1013 case 1: newitemid = 32688; break;
1014 case 2: newitemid = 32689; break;
1015 case 3: newitemid = 32690; break;
1016 case 4: newitemid = 32691; break;
1017 case 5: newitemid = 32692; break;
1018 case 6: newitemid = 32693; break;
1019 case 7: newitemid = 32700; break;
1020 case 8: newitemid = 32701; break;
1021 case 9: newitemid = 32702; break;
1022 case 10: newitemid = 32703; break;
1023 case 11: newitemid = 32704; break;
1024 case 12: newitemid = 32705; break;
1025 case 13: newitemid = 32706; break;
1026 case 14: newitemid = 32707; break;
1027 case 15: newitemid = 32708; break;
1028 case 16: newitemid = 32709; break;
1029 case 17: newitemid = 32710; break;
1030 case 18: newitemid = 32711; break;
1031 case 19: newitemid = 32712; break;
1032 case 20: newitemid = 32713; break;
1033 default:
1034 return;
1037 DoCreateItem(i,newitemid);
1038 return;
1040 // Demon Broiled Surprise
1041 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1042 case 43723:
1044 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1045 return;
1047 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1048 return;
1051 case 44875: // Complete Raptor Capture
1053 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1054 return;
1056 Creature* creatureTarget = (Creature*)unitTarget;
1058 creatureTarget->setDeathState(JUST_DIED);
1059 creatureTarget->RemoveCorpse();
1060 creatureTarget->SetHealth(0); // just for nice GM-mode view
1062 //cast spell Raptor Capture Credit
1063 m_caster->CastSpell(m_caster,42337,true,NULL);
1064 return;
1066 case 37573: //Temporal Phase Modulator
1068 if(!unitTarget)
1069 return;
1071 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1072 if(!tempSummon)
1073 return;
1075 uint32 health = tempSummon->GetHealth();
1076 const uint32 entry_list[6] = {21821, 21820, 21817};
1078 float x = tempSummon->GetPositionX();
1079 float y = tempSummon->GetPositionY();
1080 float z = tempSummon->GetPositionZ();
1081 float o = tempSummon->GetOrientation();
1083 tempSummon->UnSummon();
1085 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1086 if (!pCreature)
1087 return;
1089 pCreature->SetHealth(health);
1091 if(pCreature->AI())
1092 pCreature->AI()->AttackStart(m_caster);
1094 return;
1096 case 34665: //Administer Antidote
1098 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1099 return;
1101 if(!unitTarget)
1102 return;
1104 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1105 if(!tempSummon)
1106 return;
1108 uint32 health = tempSummon->GetHealth();
1110 float x = tempSummon->GetPositionX();
1111 float y = tempSummon->GetPositionY();
1112 float z = tempSummon->GetPositionZ();
1113 float o = tempSummon->GetOrientation();
1114 tempSummon->UnSummon();
1116 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1117 if (!pCreature)
1118 return;
1120 pCreature->SetHealth(health);
1121 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1123 if (pCreature->AI())
1124 pCreature->AI()->AttackStart(m_caster);
1126 return;
1128 case 44997: // Converting Sentry
1130 //Converted Sentry Credit
1131 m_caster->CastSpell(m_caster, 45009, true);
1132 return;
1134 case 45030: // Impale Emissary
1136 // Emissary of Hate Credit
1137 m_caster->CastSpell(m_caster, 45088, true);
1138 return;
1140 case 50243: // Teach Language
1142 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1143 return;
1145 // spell has a 1/3 chance to trigger one of the below
1146 if(roll_chance_i(66))
1147 return;
1148 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1150 // 1000001 - gnomish binary
1151 m_caster->CastSpell(m_caster, 50242, true);
1153 else
1155 // 01001000 - goblin binary
1156 m_caster->CastSpell(m_caster, 50246, true);
1159 return;
1161 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1163 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1164 return;
1166 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1167 bg->EventPlayerDroppedFlag((Player*)m_caster);
1169 m_caster->CastSpell(m_caster, 30452, true, NULL);
1170 return;
1172 case 53341:
1173 case 53343:
1175 m_caster->CastSpell(m_caster,54586,true);
1176 return;
1180 //All IconID Check in there
1181 switch(m_spellInfo->SpellIconID)
1183 // Berserking (troll racial traits)
1184 case 1661:
1186 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1187 int32 melee_mod = 10;
1188 if (healthPerc <= 40)
1189 melee_mod = 30;
1190 if (healthPerc < 100 && healthPerc > 40)
1191 melee_mod = 10+(100-healthPerc)/3;
1193 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1194 int32 hasteModBasePoints1 = (5-melee_mod);
1195 int32 hasteModBasePoints2 = 5;
1197 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1198 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1199 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1200 return;
1203 break;
1205 case SPELLFAMILY_MAGE:
1206 switch(m_spellInfo->Id )
1208 case 11958: // Cold Snap
1210 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1211 return;
1213 // immediately finishes the cooldown on Frost spells
1214 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1215 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1217 if (itr->second->state == PLAYERSPELL_REMOVED)
1218 continue;
1220 uint32 classspell = itr->first;
1221 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1223 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1224 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1225 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1227 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1229 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1230 data << uint32(classspell);
1231 data << uint64(m_caster->GetGUID());
1232 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1235 return;
1237 case 32826:
1239 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1241 //Polymorph Cast Visual Rank 1
1242 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1243 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1245 return;
1248 break;
1249 case SPELLFAMILY_WARRIOR:
1250 // Charge
1251 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1253 int32 chargeBasePoints0 = damage;
1254 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1255 return;
1257 // Execute
1258 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1260 if(!unitTarget)
1261 return;
1263 uint32 rage = m_caster->GetPower(POWER_RAGE);
1264 // Glyph of Execution bonus
1265 if (Aura *aura = m_caster->GetDummyAura(58367))
1266 rage+=aura->GetModifier()->m_amount;
1268 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1269 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1270 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1271 m_caster->SetPower(POWER_RAGE,0);
1272 return;
1274 switch(m_spellInfo->Id)
1276 // Warrior's Wrath
1277 case 21977:
1279 if(!unitTarget)
1280 return;
1281 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1282 return;
1284 // Last Stand
1285 case 12975:
1287 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1288 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1289 return;
1292 break;
1293 case SPELLFAMILY_WARLOCK:
1294 // Life Tap
1295 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1297 // In 303 exist spirit depend
1298 uint32 spirit = m_caster->GetStat(STAT_SPIRIT);
1299 switch (m_spellInfo->Id)
1301 case 1454: damage+=spirit; break;
1302 case 1455: damage+=spirit*15/10; break;
1303 case 1456: damage+=spirit*2; break;
1304 case 11687: damage+=spirit*25/10; break;
1305 case 11688:
1306 case 11689:
1307 case 27222:
1308 case 57946: damage+=spirit*3; break;
1309 default:
1310 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1311 return;
1313 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1314 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1315 if(int32(unitTarget->GetHealth()) > damage)
1317 // Shouldn't Appear in Combat Log
1318 unitTarget->ModifyHealth(-damage);
1320 int32 mana = damage;
1321 // Improved Life Tap mod
1322 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1323 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1325 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1326 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1328 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1330 // Mana Feed
1331 int32 manaFeedVal = 0;
1332 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1333 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1335 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1336 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1338 if(manaFeedVal > 0)
1340 manaFeedVal = manaFeedVal * mana / 100;
1341 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1344 else
1345 SendCastResult(SPELL_FAILED_FIZZLE);
1346 return;
1348 break;
1349 case SPELLFAMILY_PRIEST:
1350 // Penance
1351 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1353 if (!unitTarget)
1354 return;
1356 int hurt = 0;
1357 int heal = 0;
1358 switch(m_spellInfo->Id)
1360 case 47540: hurt = 47758; heal = 47757; break;
1361 case 53005: hurt = 53001; heal = 52986; break;
1362 case 53006: hurt = 53002; heal = 52987; break;
1363 case 53007: hurt = 53003; heal = 52988; break;
1364 default:
1365 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1366 return;
1368 if (m_caster->IsFriendlyTo(unitTarget))
1369 m_caster->CastSpell(unitTarget, heal, true, 0);
1370 else
1371 m_caster->CastSpell(unitTarget, hurt, true, 0);
1372 return;
1374 switch(m_spellInfo->Id )
1376 case 28598: // Touch of Weakness triggered spell
1378 if(!unitTarget || !m_triggeredByAuraSpell)
1379 return;
1381 uint32 spellid = 0;
1382 switch(m_triggeredByAuraSpell->Id)
1384 case 2652: spellid = 2943; break; // Rank 1
1385 case 19261: spellid = 19249; break; // Rank 2
1386 case 19262: spellid = 19251; break; // Rank 3
1387 case 19264: spellid = 19252; break; // Rank 4
1388 case 19265: spellid = 19253; break; // Rank 5
1389 case 19266: spellid = 19254; break; // Rank 6
1390 case 25461: spellid = 25460; break; // Rank 7
1391 default:
1392 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1393 return;
1395 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1396 return;
1399 break;
1400 case SPELLFAMILY_DRUID:
1401 switch(m_spellInfo->Id )
1403 case 5420: // Tree of Life passive
1405 // Tree of Life area effect
1406 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1407 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1408 return;
1411 break;
1412 case SPELLFAMILY_ROGUE:
1413 switch(m_spellInfo->Id )
1415 case 5938: // Shiv
1417 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1418 return;
1420 Player *pCaster = ((Player*)m_caster);
1422 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1423 if(!item)
1424 return;
1426 // all poison enchantments is temporary
1427 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1428 if(!enchant_id)
1429 return;
1431 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1432 if(!pEnchant)
1433 return;
1435 for (int s=0;s<3;s++)
1437 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1438 continue;
1440 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1441 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1442 continue;
1444 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1447 m_caster->CastSpell(unitTarget, 5940, true);
1448 return;
1450 case 14185: // Preparation Rogue
1452 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1453 return;
1455 //immediately finishes the cooldown on certain Rogue abilities
1456 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1457 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1459 uint32 classspell = itr->first;
1460 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1462 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1464 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1466 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1467 data << uint32(classspell);
1468 data << uint64(m_caster->GetGUID());
1469 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1472 return;
1474 case 31231: // Cheat Death
1476 m_caster->CastSpell(m_caster,45182,true);
1477 return;
1480 break;
1481 case SPELLFAMILY_HUNTER:
1482 // Steady Shot
1483 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1485 if( !unitTarget || !unitTarget->isAlive())
1486 return;
1488 bool found = false;
1490 // check dazed affect
1491 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1492 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1494 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1496 found = true;
1497 break;
1501 if(found)
1502 m_damage+= damage;
1503 return;
1506 switch(m_spellInfo->Id)
1508 case 23989: //Readiness talent
1510 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1511 return;
1513 //immediately finishes the cooldown for hunter abilities
1514 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1515 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1517 uint32 classspell = itr->first;
1518 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1520 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1522 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1524 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1525 data << uint32(classspell);
1526 data << uint64(m_caster->GetGUID());
1527 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1530 return;
1532 case 37506: // Scatter Shot
1534 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1535 return;
1537 // break Auto Shot and autohit
1538 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1539 m_caster->AttackStop();
1540 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1541 return;
1544 break;
1545 case SPELLFAMILY_PALADIN:
1546 switch(m_spellInfo->SpellIconID)
1548 case 156: // Holy Shock
1550 if(!unitTarget)
1551 return;
1553 int hurt = 0;
1554 int heal = 0;
1556 switch(m_spellInfo->Id)
1558 case 20473: hurt = 25912; heal = 25914; break;
1559 case 20929: hurt = 25911; heal = 25913; break;
1560 case 20930: hurt = 25902; heal = 25903; break;
1561 case 27174: hurt = 27176; heal = 27175; break;
1562 case 33072: hurt = 33073; heal = 33074; break;
1563 case 48824: hurt = 48822; heal = 48820; break;
1564 case 48825: hurt = 48823; heal = 48821; break;
1565 default:
1566 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1567 return;
1570 if(m_caster->IsFriendlyTo(unitTarget))
1571 m_caster->CastSpell(unitTarget, heal, true, 0);
1572 else
1573 m_caster->CastSpell(unitTarget, hurt, true, 0);
1575 return;
1577 case 561: // Judgement of command
1579 if(!unitTarget)
1580 return;
1582 uint32 spell_id = m_currentBasePoints[i]+1;
1583 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1584 if(!spell_proto)
1585 return;
1587 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1589 // decreased damage (/2) for non-stunned target.
1590 SpellModifier *mod = new SpellModifier;
1591 mod->op = SPELLMOD_DAMAGE;
1592 mod->value = -50;
1593 mod->type = SPELLMOD_PCT;
1594 mod->spellId = m_spellInfo->Id;
1595 mod->mask = 0x0000020000000000LL;
1596 mod->mask2= 0LL;
1598 ((Player*)m_caster)->AddSpellMod(mod, true);
1599 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1600 // mod deleted
1601 ((Player*)m_caster)->AddSpellMod(mod, false);
1603 else
1604 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1606 return;
1610 switch(m_spellInfo->Id)
1612 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1613 case 20187:
1615 if (!unitTarget)
1616 return;
1617 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1618 return;
1620 case 31789: // Righteous Defense (step 1)
1622 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1624 // non-standard cast requirement check
1625 if (!unitTarget || unitTarget->getAttackers().empty())
1627 // clear cooldown at fail
1628 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1630 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1632 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1633 data << uint32(m_spellInfo->Id);
1634 data << uint64(m_caster->GetGUID());
1635 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1638 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1639 return;
1642 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1643 // Clear targets for eff 1
1644 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1645 ihit->effectMask &= ~(1<<1);
1647 // not empty (checked)
1648 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1650 // chance to be selected from list
1651 float chance = 100.0f/attackers.size();
1652 uint32 count=0;
1653 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1655 if(!roll_chance_f(chance))
1656 continue;
1657 ++count;
1658 AddUnitTarget((*aItr), 1);
1661 // now let next effect cast spell at each target.
1662 return;
1664 case 37877: // Blessing of Faith
1666 if(!unitTarget)
1667 return;
1669 uint32 spell_id = 0;
1670 switch(unitTarget->getClass())
1672 case CLASS_DRUID: spell_id = 37878; break;
1673 case CLASS_PALADIN: spell_id = 37879; break;
1674 case CLASS_PRIEST: spell_id = 37880; break;
1675 case CLASS_SHAMAN: spell_id = 37881; break;
1676 default: return; // ignore for not healing classes
1679 m_caster->CastSpell(m_caster,spell_id,true);
1680 return;
1683 break;
1684 case SPELLFAMILY_SHAMAN:
1685 //Shaman Rockbiter Weapon
1686 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1688 // TODO: use expect spell for enchant (if exist talent)
1689 // In 3.0.3 no mods present for rockbiter
1690 uint32 spell_id = 0;
1691 switch(m_spellInfo->Id)
1693 case 8017: spell_id = 36494; break; // Rank 1
1694 case 8018: spell_id = 36750; break; // Rank 2
1695 case 8019: spell_id = 36755; break; // Rank 3
1696 case 10399: spell_id = 36759; break; // Rank 4
1697 default:
1698 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1699 return;
1702 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1704 if(!spellInfo)
1706 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1707 return;
1710 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1711 return;
1713 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1715 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1717 if(item->IsFitToSpellRequirements(m_spellInfo))
1719 Spell *spell = new Spell(m_caster, spellInfo, true);
1721 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1722 // at calculation applied affect from Elemental Weapons talent
1723 // real enchantment damage-1
1724 spell->m_currentBasePoints[1] = damage-1;
1726 SpellCastTargets targets;
1727 targets.setItemTarget( item );
1728 spell->prepare(&targets);
1732 return;
1735 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1737 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1738 return;
1740 // Regenerate 6% of Total Mana Every 3 secs
1741 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1742 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1743 return;
1745 // Lava Lash
1746 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1748 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1749 return;
1750 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1751 if (item)
1753 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1754 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1755 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1757 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1758 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1759 (*itr)->GetCastItemGUID() == item->GetGUID())
1761 m_damage += m_damage * damage / 100;
1762 return;
1766 return;
1768 break;
1771 // pet auras
1772 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1774 m_caster->AddPetAura(petSpell);
1775 return;
1779 void Spell::EffectTriggerSpellWithValue(uint32 i)
1781 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1783 // normal case
1784 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1786 if(!spellInfo)
1788 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1789 return;
1792 int32 bp = damage;
1793 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1796 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1798 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1799 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1801 if(!spellInfo)
1803 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1804 return;
1807 finish();
1808 Spell *spell = new Spell(m_caster, spellInfo, true);
1810 SpellCastTargets targets;
1811 targets.setUnitTarget( unitTarget);
1812 spell->prepare(&targets);
1814 m_caster->SetCurrentCastedSpell(spell);
1815 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1819 void Spell::EffectForceCast(uint32 i)
1821 if( !unitTarget )
1822 return;
1824 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1826 // normal case
1827 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1829 if(!spellInfo)
1831 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1832 return;
1835 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1838 void Spell::EffectTriggerSpell(uint32 i)
1840 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1842 // special cases
1843 switch(triggered_spell_id)
1845 // Vanish
1846 case 18461:
1848 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1849 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1850 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1852 // if this spell is given to NPC it must handle rest by it's own AI
1853 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1854 return;
1856 // get highest rank of the Stealth spell
1857 uint32 spellId = 0;
1858 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1859 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1861 // only highest rank is shown in spell book, so simply check if shown in spell book
1862 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1863 continue;
1865 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1866 if (!spellInfo)
1867 continue;
1869 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1871 spellId = spellInfo->Id;
1872 break;
1876 // no Stealth spell found
1877 if (!spellId)
1878 return;
1880 // reset cooldown on it if needed
1881 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1882 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1884 m_caster->CastSpell(m_caster, spellId, true);
1885 return;
1887 // just skip
1888 case 23770: // Sayge's Dark Fortune of *
1889 // not exist, common cooldown can be implemented in scripts if need.
1890 return;
1891 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1892 case 29284:
1894 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1895 if (!spell)
1896 return;
1898 for (int i=0; i < spell->StackAmount; ++i)
1899 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1900 return;
1902 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1903 case 29286:
1905 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1906 if (!spell)
1907 return;
1909 for (int i=0; i < spell->StackAmount; ++i)
1910 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1911 return;
1913 // Righteous Defense
1914 case 31980:
1916 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1917 return;
1919 // Cloak of Shadows
1920 case 35729 :
1922 Unit::AuraMap& Auras = m_caster->GetAuras();
1923 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1925 // remove all harmful spells on you...
1926 if( // ignore positive and passive auras
1927 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1928 // ignore physical auras
1929 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1931 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1932 iter = Auras.begin();
1935 return;
1937 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1938 case 41967:
1940 if (Unit *pet = m_caster->GetPet())
1941 pet->CastSpell(pet, 28305, true);
1942 return;
1946 // normal case
1947 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1949 if(!spellInfo)
1951 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1952 return;
1955 // some triggered spells require specific equipment
1956 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1958 // main hand weapon required
1959 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1961 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1963 // skip spell if no weapon in slot or broken
1964 if(!item || item->IsBroken() )
1965 return;
1967 // skip spell if weapon not fit to triggered spell
1968 if(!item->IsFitToSpellRequirements(spellInfo))
1969 return;
1972 // offhand hand weapon required
1973 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1975 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1977 // skip spell if no weapon in slot or broken
1978 if(!item || item->IsBroken() )
1979 return;
1981 // skip spell if weapon not fit to triggered spell
1982 if(!item->IsFitToSpellRequirements(spellInfo))
1983 return;
1987 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1988 bool instant = false;
1989 for(uint32 j = i+1; j < 3; ++j)
1991 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1993 instant = true;
1994 break;
1998 if(instant)
2000 if (unitTarget)
2001 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
2003 else
2004 m_TriggerSpells.push_back(spellInfo);
2007 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
2009 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
2011 // normal case
2012 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
2014 if(!spellInfo)
2016 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
2017 m_spellInfo->Id,effect_idx,triggered_spell_id);
2018 return;
2021 if (m_CastItem)
2022 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
2024 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
2027 void Spell::EffectTeleportUnits(uint32 i)
2029 if(!unitTarget || unitTarget->isInFlight())
2030 return;
2032 switch (m_spellInfo->EffectImplicitTargetB[i])
2034 case TARGET_INNKEEPER_COORDINATES:
2036 // Only players can teleport to innkeeper
2037 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2038 return;
2040 ((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);
2041 return;
2043 case TARGET_TABLE_X_Y_Z_COORDINATES:
2045 // TODO: Only players can teleport?
2046 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2047 return;
2048 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2049 if(!st)
2051 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
2052 return;
2054 ((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);
2055 break;
2057 case TARGET_BEHIND_VICTIM:
2059 // Get selected target for player (or victim for units)
2060 Unit *pTarget = NULL;
2061 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2062 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2063 else
2064 pTarget = m_caster->getVictim();
2065 // No target present - return
2066 if (!pTarget)
2067 return;
2068 // Init dest coordinates
2069 uint32 mapid = m_caster->GetMapId();
2070 float x = m_targets.m_destX;
2071 float y = m_targets.m_destY;
2072 float z = m_targets.m_destZ;
2073 float orientation = pTarget->GetOrientation();
2074 // Teleport
2075 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2076 ((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));
2077 else
2079 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2080 WorldPacket data;
2081 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2082 unitTarget->SendMessageToSet(&data, false);
2084 return;
2086 default:
2088 // If not exist data for dest location - return
2089 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2091 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2092 return;
2094 // Init dest coordinates
2095 uint32 mapid = m_caster->GetMapId();
2096 float x = m_targets.m_destX;
2097 float y = m_targets.m_destY;
2098 float z = m_targets.m_destZ;
2099 float orientation = unitTarget->GetOrientation();
2100 // Teleport
2101 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2102 ((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));
2103 else
2105 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2106 WorldPacket data;
2107 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2108 unitTarget->SendMessageToSet(&data, false);
2110 return;
2114 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2115 switch ( m_spellInfo->Id )
2117 // Dimensional Ripper - Everlook
2118 case 23442:
2120 int32 r = irand(0, 119);
2121 if ( r >= 70 ) // 7/12 success
2123 if ( r < 100 ) // 4/12 evil twin
2124 m_caster->CastSpell(m_caster,23445,true);
2125 else // 1/12 fire
2126 m_caster->CastSpell(m_caster,23449,true);
2128 return;
2130 // Ultrasafe Transporter: Toshley's Station
2131 case 36941:
2133 if ( roll_chance_i(50) ) // 50% success
2135 int32 rand_eff = urand(1,7);
2136 switch ( rand_eff )
2138 case 1:
2139 // soul split - evil
2140 m_caster->CastSpell(m_caster,36900,true);
2141 break;
2142 case 2:
2143 // soul split - good
2144 m_caster->CastSpell(m_caster,36901,true);
2145 break;
2146 case 3:
2147 // Increase the size
2148 m_caster->CastSpell(m_caster,36895,true);
2149 break;
2150 case 4:
2151 // Decrease the size
2152 m_caster->CastSpell(m_caster,36893,true);
2153 break;
2154 case 5:
2155 // Transform
2157 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2158 m_caster->CastSpell(m_caster,36897,true);
2159 else
2160 m_caster->CastSpell(m_caster,36899,true);
2161 break;
2163 case 6:
2164 // chicken
2165 m_caster->CastSpell(m_caster,36940,true);
2166 break;
2167 case 7:
2168 // evil twin
2169 m_caster->CastSpell(m_caster,23445,true);
2170 break;
2173 return;
2175 // Dimensional Ripper - Area 52
2176 case 36890:
2178 if ( roll_chance_i(50) ) // 50% success
2180 int32 rand_eff = urand(1,4);
2181 switch ( rand_eff )
2183 case 1:
2184 // soul split - evil
2185 m_caster->CastSpell(m_caster,36900,true);
2186 break;
2187 case 2:
2188 // soul split - good
2189 m_caster->CastSpell(m_caster,36901,true);
2190 break;
2191 case 3:
2192 // Increase the size
2193 m_caster->CastSpell(m_caster,36895,true);
2194 break;
2195 case 4:
2196 // Transform
2198 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2199 m_caster->CastSpell(m_caster,36897,true);
2200 else
2201 m_caster->CastSpell(m_caster,36899,true);
2202 break;
2206 return;
2211 void Spell::EffectApplyAura(uint32 i)
2213 if(!unitTarget)
2214 return;
2216 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2217 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2218 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2219 return;
2221 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2222 if(!caster)
2223 return;
2225 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2227 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2229 // Now Reduce spell duration using data received at spell hit
2230 int32 duration = Aur->GetAuraMaxDuration();
2231 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2232 Aur->setDiminishGroup(m_diminishGroup);
2234 // if Aura removed and deleted, do not continue.
2235 if(duration== 0 && !(Aur->IsPermanent()))
2237 delete Aur;
2238 return;
2241 if(duration != Aur->GetAuraMaxDuration())
2243 Aur->SetAuraMaxDuration(duration);
2244 Aur->SetAuraDuration(duration);
2247 bool added = unitTarget->AddAura(Aur);
2249 // Aura not added and deleted in AddAura call;
2250 if (!added)
2251 return;
2253 // found crash at character loading, broken pointer to Aur...
2254 // Aur was deleted in AddAura()...
2255 if(!Aur)
2256 return;
2258 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2259 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2260 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2263 void Spell::EffectUnlearnSpecialization( uint32 i )
2265 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2266 return;
2268 Player *_player = (Player*)unitTarget;
2269 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2271 _player->removeSpell(spellToUnlearn);
2273 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2276 void Spell::EffectPowerDrain(uint32 i)
2278 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2279 return;
2281 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2283 if(!unitTarget)
2284 return;
2285 if(!unitTarget->isAlive())
2286 return;
2287 if(unitTarget->getPowerType() != drain_power)
2288 return;
2289 if(damage < 0)
2290 return;
2292 uint32 curPower = unitTarget->GetPower(drain_power);
2294 //add spell damage bonus
2295 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2297 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2298 uint32 power = damage;
2299 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2300 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2302 int32 new_damage;
2303 if(curPower < power)
2304 new_damage = curPower;
2305 else
2306 new_damage = power;
2308 unitTarget->ModifyPower(drain_power,-new_damage);
2310 // Don`t restore from self drain
2311 if(drain_power == POWER_MANA && m_caster != unitTarget)
2313 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2314 if(manaMultiplier==0)
2315 manaMultiplier = 1;
2317 if(Player *modOwner = m_caster->GetSpellModOwner())
2318 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2320 int32 gain = int32(new_damage*manaMultiplier);
2322 m_caster->ModifyPower(POWER_MANA,gain);
2323 //send log
2324 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2328 void Spell::EffectSendEvent(uint32 EffectIndex)
2330 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2332 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2333 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2335 switch(m_spellInfo->Id)
2337 case 23333: // Pickup Horde Flag
2338 /*do not uncomment .
2339 if(bg->GetTypeID()==BATTLEGROUND_WS)
2340 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2341 sLog.outDebug("Send Event Horde Flag Picked Up");
2342 break;
2343 /* not used :
2344 case 23334: // Drop Horde Flag
2345 if(bg->GetTypeID()==BATTLEGROUND_WS)
2346 bg->EventPlayerDroppedFlag((Player*)m_caster);
2347 sLog.outDebug("Drop Horde Flag");
2348 break;
2350 case 23335: // Pickup Alliance Flag
2351 /*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
2352 if(bg->GetTypeID()==BATTLEGROUND_WS)
2353 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2354 sLog.outDebug("Send Event Alliance Flag Picked Up");
2355 break;
2356 /* not used :
2357 case 23336: // Drop Alliance Flag
2358 if(bg->GetTypeID()==BATTLEGROUND_WS)
2359 bg->EventPlayerDroppedFlag((Player*)m_caster);
2360 sLog.outDebug("Drop Alliance Flag");
2361 break;
2362 case 23385: // Alliance Flag Returns
2363 if(bg->GetTypeID()==BATTLEGROUND_WS)
2364 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2365 sLog.outDebug("Alliance Flag Returned");
2366 break;
2367 case 23386: // Horde Flag Returns
2368 if(bg->GetTypeID()==BATTLEGROUND_WS)
2369 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2370 sLog.outDebug("Horde Flag Returned");
2371 break;*/
2372 case 34976:
2374 if(bg->GetTypeID()==BATTLEGROUND_EY)
2375 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2377 break;
2378 default:
2379 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2380 break;
2384 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2385 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2388 void Spell::EffectPowerBurn(uint32 i)
2390 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2391 return;
2393 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2395 if(!unitTarget)
2396 return;
2397 if(!unitTarget->isAlive())
2398 return;
2399 if(unitTarget->getPowerType()!=powertype)
2400 return;
2401 if(damage < 0)
2402 return;
2404 int32 curPower = int32(unitTarget->GetPower(powertype));
2406 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2407 uint32 power = damage;
2408 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2409 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2411 int32 new_damage = (curPower < power) ? curPower : power;
2413 unitTarget->ModifyPower(powertype,-new_damage);
2414 float multiplier = m_spellInfo->EffectMultipleValue[i];
2416 if(Player *modOwner = m_caster->GetSpellModOwner())
2417 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2419 new_damage = int32(new_damage*multiplier);
2420 m_damage+=new_damage;
2423 void Spell::EffectHeal( uint32 /*i*/ )
2425 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2427 // Try to get original caster
2428 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2430 // Skip if m_originalCaster not available
2431 if (!caster)
2432 return;
2434 int32 addhealth = damage;
2436 // Vessel of the Naaru (Vial of the Sunwell trinket)
2437 if (m_spellInfo->Id == 45064)
2439 // Amount of heal - depends from stacked Holy Energy
2440 int damageAmount = 0;
2441 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2442 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2443 if((*i)->GetId() == 45062)
2444 damageAmount+=(*i)->GetModifier()->m_amount;
2445 if (damageAmount)
2446 m_caster->RemoveAurasDueToSpell(45062);
2448 addhealth += damageAmount;
2450 // Swiftmend - consumes Regrowth or Rejuvenation
2451 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2453 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2454 // find most short by duration
2455 Aura *targetAura = NULL;
2456 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2458 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2459 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2461 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2462 targetAura = *i;
2466 if(!targetAura)
2468 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2469 return;
2471 int idx = 0;
2472 while(idx < 3)
2474 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2475 break;
2476 idx++;
2479 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2480 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2481 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2483 addhealth += tickheal * tickcount;
2485 else
2486 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2488 m_healing+=addhealth;
2492 void Spell::EffectHealPct( uint32 /*i*/ )
2494 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2496 // Try to get original caster
2497 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2499 // Skip if m_originalCaster not available
2500 if (!caster)
2501 return;
2503 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2504 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2506 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2507 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2509 if(caster->GetTypeId()==TYPEID_PLAYER)
2510 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2511 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2515 void Spell::EffectHealMechanical( uint32 /*i*/ )
2517 // Mechanic creature type should be correctly checked by targetCreatureType field
2518 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2520 // Try to get original caster
2521 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2523 // Skip if m_originalCaster not available
2524 if (!caster)
2525 return;
2527 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2528 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2529 unitTarget->ModifyHealth( int32(damage) );
2533 void Spell::EffectHealthLeech(uint32 i)
2535 if(!unitTarget)
2536 return;
2537 if(!unitTarget->isAlive())
2538 return;
2540 if(damage < 0)
2541 return;
2543 sLog.outDebug("HealthLeech :%i", damage);
2545 float multiplier = m_spellInfo->EffectMultipleValue[i];
2547 if(Player *modOwner = m_caster->GetSpellModOwner())
2548 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2550 int32 new_damage = int32(damage*multiplier);
2551 uint32 curHealth = unitTarget->GetHealth();
2552 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2553 if(curHealth < new_damage)
2554 new_damage = curHealth;
2556 if(m_caster->isAlive())
2558 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2560 m_caster->ModifyHealth(new_damage);
2562 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2563 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2565 // m_healthLeech+=tmpvalue;
2566 // m_damage+=new_damage;
2569 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2571 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2572 return;
2574 Player* player = (Player*)unitTarget;
2576 uint32 newitemid = itemtype;
2577 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2578 if(!pProto)
2580 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2581 return;
2584 uint32 num_to_add;
2586 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2587 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2589 int32 basePoints = m_currentBasePoints[i];
2590 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2591 if (randomPoints)
2592 num_to_add = basePoints + irand(1, randomPoints);
2593 else
2594 num_to_add = basePoints + 1;
2596 else if (pProto->MaxCount == 1)
2597 num_to_add = 1;
2598 else if(player->getLevel() >= m_spellInfo->spellLevel)
2600 int32 basePoints = m_currentBasePoints[i];
2601 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2602 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2604 else
2605 num_to_add = 2;
2607 if (num_to_add < 1)
2608 num_to_add = 1;
2609 if (num_to_add > pProto->GetMaxStackSize())
2610 num_to_add = pProto->GetMaxStackSize();
2612 // init items_count to 1, since 1 item will be created regardless of specialization
2613 int items_count=1;
2614 // the chance to create additional items
2615 float additionalCreateChance=0.0f;
2616 // the maximum number of created additional items
2617 uint8 additionalMaxNum=0;
2618 // get the chance and maximum number for creating extra items
2619 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2621 // roll with this chance till we roll not to create or we create the max num
2622 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2623 ++items_count;
2626 // really will be created more items
2627 num_to_add *= items_count;
2629 // can the player store the new item?
2630 ItemPosCountVec dest;
2631 uint32 no_space = 0;
2632 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2633 if( msg != EQUIP_ERR_OK )
2635 // convert to possible store amount
2636 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2637 num_to_add -= no_space;
2638 else
2640 // if not created by another reason from full inventory or unique items amount limitation
2641 player->SendEquipError( msg, NULL, NULL );
2642 return;
2646 if(num_to_add)
2648 // create the new item and store it
2649 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2651 // was it successful? return error if not
2652 if(!pItem)
2654 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2655 return;
2658 // set the "Crafted by ..." property of the item
2659 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2660 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2662 // send info to the client
2663 if(pItem)
2664 player->SendNewItem(pItem, num_to_add, true, true);
2666 // we succeeded in creating at least one item, so a levelup is possible
2667 player->UpdateCraftSkill(m_spellInfo->Id);
2670 // for battleground marks send by mail if not add all expected
2671 if(no_space > 0 )
2673 BattleGroundTypeId bgType;
2674 switch(m_spellInfo->Id)
2676 case SPELL_AV_MARK_WINNER:
2677 case SPELL_AV_MARK_LOSER:
2678 bgType = BATTLEGROUND_AV;
2679 break;
2680 case SPELL_WS_MARK_WINNER:
2681 case SPELL_WS_MARK_LOSER:
2682 bgType = BATTLEGROUND_WS;
2683 break;
2684 case SPELL_AB_MARK_WINNER:
2685 case SPELL_AB_MARK_LOSER:
2686 bgType = BATTLEGROUND_AB;
2687 break;
2688 default:
2689 return;
2692 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2693 bg->SendRewardMarkByMail(player,newitemid,no_space);
2697 void Spell::EffectCreateItem(uint32 i)
2699 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2702 void Spell::EffectPersistentAA(uint32 i)
2704 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2706 if(Player* modOwner = m_caster->GetSpellModOwner())
2707 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2709 int32 duration = GetSpellDuration(m_spellInfo);
2710 DynamicObject* dynObj = new DynamicObject;
2711 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))
2713 delete dynObj;
2714 return;
2716 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2717 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2718 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2719 m_caster->AddDynObject(dynObj);
2720 dynObj->GetMap()->Add(dynObj);
2723 void Spell::EffectEnergize(uint32 i)
2725 if(!unitTarget)
2726 return;
2727 if(!unitTarget->isAlive())
2728 return;
2730 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2731 return;
2733 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2735 // Some level depends spells
2736 int multiplier = 0;
2737 int level_diff = 0;
2738 switch (m_spellInfo->Id)
2740 // Restore Energy
2741 case 9512:
2742 level_diff = m_caster->getLevel() - 40;
2743 multiplier = 2;
2744 break;
2745 // Blood Fury
2746 case 24571:
2747 level_diff = m_caster->getLevel() - 60;
2748 multiplier = 10;
2749 break;
2750 // Burst of Energy
2751 case 24532:
2752 level_diff = m_caster->getLevel() - 60;
2753 multiplier = 4;
2754 break;
2755 default:
2756 break;
2759 if (level_diff > 0)
2760 damage -= multiplier * level_diff;
2762 if(damage < 0)
2763 return;
2765 if(unitTarget->GetMaxPower(power) == 0)
2766 return;
2768 unitTarget->ModifyPower(power,damage);
2769 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2771 // Mad Alchemist's Potion
2772 if (m_spellInfo->Id == 45051)
2774 // find elixirs on target
2775 uint32 elixir_mask = 0;
2776 Unit::AuraMap& Auras = unitTarget->GetAuras();
2777 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2779 uint32 spell_id = itr->second->GetId();
2780 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2781 elixir_mask |= mask;
2784 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2785 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2787 // get all available elixirs by mask and spell level
2788 std::vector<uint32> elixirs;
2789 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2790 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2792 if (itr->second & elixir_mask)
2794 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2795 continue;
2797 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2798 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2799 continue;
2801 elixirs.push_back(itr->first);
2805 if (!elixirs.empty())
2807 // cast random elixir on target
2808 uint32 rand_spell = urand(0,elixirs.size()-1);
2809 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2814 void Spell::EffectEnergisePct(uint32 i)
2816 if(!unitTarget)
2817 return;
2818 if(!unitTarget->isAlive())
2819 return;
2821 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2822 return;
2824 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2826 uint32 maxPower = unitTarget->GetMaxPower(power);
2827 if(maxPower == 0)
2828 return;
2830 uint32 gain = damage * maxPower / 100;
2831 unitTarget->ModifyPower(power, gain);
2832 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2835 void Spell::SendLoot(uint64 guid, LootType loottype)
2837 Player* player = (Player*)m_caster;
2838 if (!player)
2839 return;
2841 if (gameObjTarget)
2843 if (Script->GOHello(player, gameObjTarget))
2844 return;
2846 switch (gameObjTarget->GetGoType())
2848 case GAMEOBJECT_TYPE_DOOR:
2849 case GAMEOBJECT_TYPE_BUTTON:
2850 gameObjTarget->UseDoorOrButton();
2851 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2852 return;
2854 case GAMEOBJECT_TYPE_QUESTGIVER:
2855 // start or end quest
2856 player->PrepareQuestMenu(guid);
2857 player->SendPreparedQuest(guid);
2858 return;
2860 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2861 // triggering linked GO
2862 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2863 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2864 return;
2866 case GAMEOBJECT_TYPE_GOOBER:
2867 // goober_scripts can be triggered if the player don't have the quest
2868 if (gameObjTarget->GetGOInfo()->goober.eventId)
2870 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2871 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2874 // cast goober spell
2875 if (gameObjTarget->GetGOInfo()->goober.questId)
2876 ///Quest require to be active for GO using
2877 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2878 return;
2880 gameObjTarget->AddUniqueUse(player);
2881 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2883 //TODO? Objective counting called without spell check but with quest objective check
2884 // if send spell id then this line will duplicate to spell casting call (double counting)
2885 // So we or have this line and not required in quest_template have reqSpellIdN
2886 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2887 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2889 // triggering linked GO
2890 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2891 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2893 return;
2895 case GAMEOBJECT_TYPE_CHEST:
2896 // TODO: possible must be moved to loot release (in different from linked triggering)
2897 if (gameObjTarget->GetGOInfo()->chest.eventId)
2899 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2900 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2903 // triggering linked GO
2904 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2905 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2907 // Don't return, let loots been taken
2911 // Send loot
2912 player->SendLoot(guid, loottype);
2915 void Spell::EffectOpenLock(uint32 /*i*/)
2917 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2919 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2920 return;
2923 Player* player = (Player*)m_caster;
2925 LootType loottype = LOOT_CORPSE;
2926 uint32 lockId = 0;
2927 uint64 guid = 0;
2929 // Get lockId
2930 if(gameObjTarget)
2932 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2933 // Arathi Basin banner opening !
2934 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2935 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2937 //isAllowUseBattleGroundObject() already called in CanCast()
2938 // in battleground check
2939 if(BattleGround *bg = player->GetBattleGround())
2941 // check if it's correct bg
2942 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2943 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2944 return;
2947 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2949 //isAllowUseBattleGroundObject() already called in CanCast()
2950 // in battleground check
2951 if(BattleGround *bg = player->GetBattleGround())
2953 if(bg->GetTypeID() == BATTLEGROUND_EY)
2954 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2955 return;
2958 lockId = gameObjTarget->GetLockId();
2959 guid = gameObjTarget->GetGUID();
2961 else if(itemTarget)
2963 lockId = itemTarget->GetProto()->LockID;
2964 guid = itemTarget->GetGUID();
2966 else
2968 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2969 return;
2972 if(!lockId) // possible case for GO and maybe for items.
2974 SendLoot(guid, loottype);
2975 return;
2978 // Get LockInfo
2979 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2981 if (!lockInfo)
2983 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2984 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2985 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2986 return;
2989 // check key
2990 for(int i = 0; i < 8; ++i)
2992 // Type==1 This means lockInfo->Index[i] is an item
2993 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2995 SendLoot(guid, loottype);
2996 return;
3000 uint32 SkillId = 0;
3001 // Check and skill-up skill
3002 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
3003 SkillId = m_spellInfo->EffectMiscValue[1];
3004 // pickpocketing spells
3005 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
3006 SkillId = SKILL_LOCKPICKING;
3008 // skill bonus provided by casting spell (mostly item spells)
3009 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
3011 uint32 reqSkillValue = lockInfo->Skill[0];
3013 if(lockInfo->Skill[1]) // required pick lock skill applying
3015 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
3017 SendCastResult(SPELL_FAILED_FIZZLE);
3018 return;
3021 reqSkillValue = lockInfo->Skill[1];
3023 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
3025 SendCastResult(SPELL_FAILED_BAD_TARGETS);
3026 return;
3029 if ( SkillId )
3031 loottype = LOOT_SKINNING;
3032 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
3034 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3035 return;
3038 // update skill if really known
3039 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3040 if(SkillValue) // non only item base skill
3042 if(gameObjTarget)
3044 // Allow one skill-up until respawned
3045 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3046 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3047 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3049 else if(itemTarget)
3051 // Do one skill-up
3052 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3053 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3058 SendLoot(guid, loottype);
3061 void Spell::EffectSummonChangeItem(uint32 i)
3063 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3064 return;
3066 Player *player = (Player*)m_caster;
3068 // applied only to using item
3069 if(!m_CastItem)
3070 return;
3072 // ... only to item in own inventory/bank/equip_slot
3073 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3074 return;
3076 uint32 newitemid = m_spellInfo->EffectItemType[i];
3077 if(!newitemid)
3078 return;
3080 uint16 pos = m_CastItem->GetPos();
3082 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3083 if( !pNewItem )
3084 return;
3086 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3088 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3089 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3092 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3094 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3095 player->DurabilityLoss(pNewItem, loosePercent);
3098 if( player->IsInventoryPos( pos ) )
3100 ItemPosCountVec dest;
3101 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3102 if( msg == EQUIP_ERR_OK )
3104 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3106 // prevent crash at access and unexpected charges counting with item update queue corrupt
3107 if(m_CastItem==m_targets.getItemTarget())
3108 m_targets.setItemTarget(NULL);
3110 m_CastItem = NULL;
3112 player->StoreItem( dest, pNewItem, true);
3113 return;
3116 else if( player->IsBankPos ( pos ) )
3118 ItemPosCountVec dest;
3119 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3120 if( msg == EQUIP_ERR_OK )
3122 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3124 // prevent crash at access and unexpected charges counting with item update queue corrupt
3125 if(m_CastItem==m_targets.getItemTarget())
3126 m_targets.setItemTarget(NULL);
3128 m_CastItem = NULL;
3130 player->BankItem( dest, pNewItem, true);
3131 return;
3134 else if( player->IsEquipmentPos ( pos ) )
3136 uint16 dest;
3137 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3138 if( msg == EQUIP_ERR_OK )
3140 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3142 // prevent crash at access and unexpected charges counting with item update queue corrupt
3143 if(m_CastItem==m_targets.getItemTarget())
3144 m_targets.setItemTarget(NULL);
3146 m_CastItem = NULL;
3148 player->EquipItem( dest, pNewItem, true);
3149 player->AutoUnequipOffhandIfNeed();
3150 return;
3154 // fail
3155 delete pNewItem;
3158 void Spell::EffectOpenSecretSafe(uint32 i)
3160 EffectOpenLock(i); //no difference for now
3163 void Spell::EffectProficiency(uint32 /*i*/)
3165 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3166 return;
3167 Player *p_target = (Player*)unitTarget;
3169 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3170 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3172 p_target->AddWeaponProficiency(subClassMask);
3173 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3175 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3177 p_target->AddArmorProficiency(subClassMask);
3178 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3182 void Spell::EffectApplyAreaAura(uint32 i)
3184 if(!unitTarget)
3185 return;
3186 if(!unitTarget->isAlive())
3187 return;
3189 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3190 unitTarget->AddAura(Aur);
3193 void Spell::EffectSummonType(uint32 i)
3195 switch(m_spellInfo->EffectMiscValueB[i])
3197 case SUMMON_TYPE_GUARDIAN:
3198 case SUMMON_TYPE_POSESSED:
3199 case SUMMON_TYPE_POSESSED2:
3200 case SUMMON_TYPE_FORCE_OF_NATURE:
3201 case SUMMON_TYPE_GUARDIAN2:
3202 EffectSummonGuardian(i);
3203 break;
3204 case SUMMON_TYPE_WILD:
3205 EffectSummonWild(i);
3206 break;
3207 case SUMMON_TYPE_DEMON:
3208 EffectSummonDemon(i);
3209 break;
3210 case SUMMON_TYPE_SUMMON:
3211 EffectSummon(i);
3212 break;
3213 case SUMMON_TYPE_CRITTER:
3214 case SUMMON_TYPE_CRITTER2:
3215 case SUMMON_TYPE_CRITTER3:
3216 EffectSummonCritter(i);
3217 break;
3218 case SUMMON_TYPE_TOTEM_SLOT1:
3219 case SUMMON_TYPE_TOTEM_SLOT2:
3220 case SUMMON_TYPE_TOTEM_SLOT3:
3221 case SUMMON_TYPE_TOTEM_SLOT4:
3222 case SUMMON_TYPE_TOTEM:
3223 EffectSummonTotem(i);
3224 break;
3225 case SUMMON_TYPE_UNKNOWN1:
3226 case SUMMON_TYPE_UNKNOWN2:
3227 case SUMMON_TYPE_UNKNOWN3:
3228 case SUMMON_TYPE_UNKNOWN4:
3229 case SUMMON_TYPE_UNKNOWN5:
3230 break;
3231 default:
3232 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3233 break;
3237 void Spell::EffectSummon(uint32 i)
3239 if(m_caster->GetPetGUID())
3240 return;
3242 if(!unitTarget)
3243 return;
3244 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3245 if(!pet_entry)
3246 return;
3247 uint32 level = m_caster->getLevel();
3248 Pet* spawnCreature = new Pet(SUMMON_PET);
3250 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3252 // set timer for unsummon
3253 int32 duration = GetSpellDuration(m_spellInfo);
3254 if(duration > 0)
3255 spawnCreature->SetDuration(duration);
3257 return;
3260 Map *map = m_caster->GetMap();
3261 uint32 pet_number = objmgr.GeneratePetNumber();
3262 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3264 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3265 delete spawnCreature;
3266 return;
3269 // Summon in dest location
3270 float x,y,z;
3271 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3273 x = m_targets.m_destX;
3274 y = m_targets.m_destY;
3275 z = m_targets.m_destZ;
3277 else
3278 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3280 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3282 if(!spawnCreature->IsPositionValid())
3284 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3285 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3286 delete spawnCreature;
3287 return;
3290 // set timer for unsummon
3291 int32 duration = GetSpellDuration(m_spellInfo);
3292 if(duration > 0)
3293 spawnCreature->SetDuration(duration);
3295 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3296 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3297 spawnCreature->setPowerType(POWER_MANA);
3298 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3299 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3300 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3301 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3302 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3303 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3304 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3305 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3306 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3308 spawnCreature->InitStatsForLevel(level);
3310 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3312 spawnCreature->AIM_Initialize();
3313 spawnCreature->InitPetCreateSpells();
3314 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3315 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3317 std::string name = m_caster->GetName();
3318 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3319 spawnCreature->SetName( name );
3321 map->Add((Creature*)spawnCreature);
3323 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3325 m_caster->SetPet(spawnCreature);
3326 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3327 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3328 ((Player*)m_caster)->PetSpellInitialize();
3332 void Spell::EffectLearnSpell(uint32 i)
3334 if(!unitTarget)
3335 return;
3337 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3339 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3340 EffectLearnPetSpell(i);
3342 return;
3345 Player *player = (Player*)unitTarget;
3347 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3348 player->learnSpell(spellToLearn);
3350 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3353 void Spell::EffectDispel(uint32 i)
3355 if(!unitTarget)
3356 return;
3358 // Fill possible dispell list
3359 std::vector <Aura *> dispel_list;
3361 // Create dispel mask by dispel type
3362 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3363 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3364 Unit::AuraMap const& auras = unitTarget->GetAuras();
3365 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3367 Aura *aur = (*itr).second;
3368 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3370 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3372 bool positive = true;
3373 if (!aur->IsPositive())
3374 positive = false;
3375 else
3376 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3378 // do not remove positive auras if friendly target
3379 // negative auras if non-friendly target
3380 if(positive == unitTarget->IsFriendlyTo(m_caster))
3381 continue;
3383 // Add aura to dispel list
3384 dispel_list.push_back(aur);
3387 // Ok if exist some buffs for dispel try dispel it
3388 if (!dispel_list.empty())
3390 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3391 std::list < uint32 > fail_list; // spell_id
3392 int32 list_size = dispel_list.size();
3393 // Dispell N = damage buffs (or while exist buffs for dispel)
3394 for (int32 count=0; count < damage && list_size > 0; ++count)
3396 // Random select buff for dispel
3397 Aura *aur = dispel_list[urand(0, list_size-1)];
3399 SpellEntry const* spellInfo = aur->GetSpellProto();
3400 // Base dispel chance
3401 // TODO: possible chance depend from spell level??
3402 int32 miss_chance = 0;
3403 // Apply dispel mod from aura caster
3404 if (Unit *caster = aur->GetCaster())
3406 if ( Player* modOwner = caster->GetSpellModOwner() )
3407 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3409 // Try dispel
3410 if (roll_chance_i(miss_chance))
3411 fail_list.push_back(aur->GetId());
3412 else
3413 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3414 // Remove buff from list for prevent doubles
3415 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3417 Aura *dispeled = *j;
3418 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3420 j = dispel_list.erase(j);
3421 --list_size;
3423 else
3424 ++j;
3427 // Send success log and really remove auras
3428 if (!success_list.empty())
3430 int32 count = success_list.size();
3431 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3432 data.append(unitTarget->GetPackGUID()); // Victim GUID
3433 data.append(m_caster->GetPackGUID()); // Caster GUID
3434 data << uint32(m_spellInfo->Id); // Dispell spell id
3435 data << uint8(0); // not used
3436 data << uint32(count); // count
3437 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3439 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3440 data << uint32(spellInfo->Id); // Spell Id
3441 data << uint8(0); // 0 - dispeled !=0 cleansed
3442 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3444 m_caster->SendMessageToSet(&data, true);
3446 // On succes dispel
3447 // Devour Magic
3448 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3450 uint32 heal_spell = 0;
3451 switch (m_spellInfo->Id)
3453 case 19505: heal_spell = 19658; break;
3454 case 19731: heal_spell = 19732; break;
3455 case 19734: heal_spell = 19733; break;
3456 case 19736: heal_spell = 19735; break;
3457 case 27276: heal_spell = 27278; break;
3458 case 27277: heal_spell = 27279; break;
3459 default:
3460 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3461 break;
3463 if (heal_spell)
3464 m_caster->CastSpell(m_caster, heal_spell, true);
3467 // Send fail log to client
3468 if (!fail_list.empty())
3470 // Failed to dispell
3471 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3472 data << uint64(m_caster->GetGUID()); // Caster GUID
3473 data << uint64(unitTarget->GetGUID()); // Victim GUID
3474 data << uint32(m_spellInfo->Id); // Dispell spell id
3475 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3476 data << uint32(*j); // Spell Id
3477 m_caster->SendMessageToSet(&data, true);
3482 void Spell::EffectDualWield(uint32 /*i*/)
3484 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3485 ((Player*)unitTarget)->SetCanDualWield(true);
3488 void Spell::EffectPull(uint32 /*i*/)
3490 // TODO: create a proper pull towards distract spell center for distract
3491 sLog.outDebug("WORLD: Spell Effect DUMMY");
3494 void Spell::EffectDistract(uint32 /*i*/)
3496 // Check for possible target
3497 if (!unitTarget || unitTarget->isInCombat())
3498 return;
3500 // target must be OK to do this
3501 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3502 return;
3504 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3506 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3508 // For players just turn them
3509 WorldPacket data;
3510 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3511 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3512 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3514 else
3516 // Set creature Distracted, Stop it, And turn it
3517 unitTarget->SetOrientation(angle);
3518 unitTarget->StopMoving();
3519 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3523 void Spell::EffectPickPocket(uint32 /*i*/)
3525 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3526 return;
3528 // victim must be creature and attackable
3529 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3530 return;
3532 // victim have to be alive and humanoid or undead
3533 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3535 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3537 if (chance > irand(0, 19))
3539 // Stealing successful
3540 //sLog.outDebug("Sending loot from pickpocket");
3541 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3543 else
3545 // Reveal action + get attack
3546 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3547 if (((Creature*)unitTarget)->AI())
3548 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3553 void Spell::EffectAddFarsight(uint32 i)
3555 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3556 int32 duration = GetSpellDuration(m_spellInfo);
3557 DynamicObject* dynObj = new DynamicObject;
3558 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))
3560 delete dynObj;
3561 return;
3563 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3564 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3565 m_caster->AddDynObject(dynObj);
3566 dynObj->GetMap()->Add(dynObj);
3567 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3568 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3571 void Spell::EffectSummonWild(uint32 i)
3573 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3574 if(!creature_entry)
3575 return;
3577 uint32 level = m_caster->getLevel();
3579 // level of creature summoned using engineering item based at engineering skill level
3580 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3582 ItemPrototype const *proto = m_CastItem->GetProto();
3583 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3585 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3586 if(skill202)
3588 level = skill202/5;
3593 // select center of summon position
3594 float center_x = m_targets.m_destX;
3595 float center_y = m_targets.m_destY;
3596 float center_z = m_targets.m_destZ;
3598 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3600 int32 amount = damage > 0 ? damage : 1;
3602 for(int32 count = 0; count < amount; ++count)
3604 float px, py, pz;
3605 // If dest location if present
3606 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3608 // Summon 1 unit in dest location
3609 if (count == 0)
3611 px = m_targets.m_destX;
3612 py = m_targets.m_destY;
3613 pz = m_targets.m_destZ;
3615 // Summon in random point all other units if location present
3616 else
3617 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3619 // Summon if dest location not present near caster
3620 else
3621 m_caster->GetClosePoint(px,py,pz,3.0f);
3623 int32 duration = GetSpellDuration(m_spellInfo);
3625 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3627 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3631 void Spell::EffectSummonGuardian(uint32 i)
3633 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3634 if(!pet_entry)
3635 return;
3637 // Jewelery statue case (totem like)
3638 if(m_spellInfo->SpellIconID==2056)
3640 EffectSummonTotem(i);
3641 return;
3644 // set timer for unsummon
3645 int32 duration = GetSpellDuration(m_spellInfo);
3647 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3648 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3649 // so this code hack in fact
3650 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3651 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3652 return; // find old guardian, ignore summon
3654 // in another case summon new
3655 uint32 level = m_caster->getLevel();
3657 // level of pet summoned using engineering item based at engineering skill level
3658 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3660 ItemPrototype const *proto = m_CastItem->GetProto();
3661 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3663 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3664 if(skill202)
3666 level = skill202/5;
3671 // select center of summon position
3672 float center_x = m_targets.m_destX;
3673 float center_y = m_targets.m_destY;
3674 float center_z = m_targets.m_destZ;
3676 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3678 int32 amount = damage > 0 ? damage : 1;
3680 for(int32 count = 0; count < amount; ++count)
3682 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3684 Map *map = m_caster->GetMap();
3685 uint32 pet_number = objmgr.GeneratePetNumber();
3686 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,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 i)
3805 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3806 return;
3807 if (!itemTarget)
3808 return;
3810 Player* p_caster = (Player*)m_caster;
3812 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3814 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3815 if (!enchant_id)
3816 return;
3818 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3819 if(!pEnchant)
3820 return;
3822 // item can be in trade slot and have owner diff. from caster
3823 Player* item_owner = itemTarget->GetOwner();
3824 if(!item_owner)
3825 return;
3827 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3829 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3830 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3831 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3832 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3835 // remove old enchanting before applying new if equipped
3836 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3838 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3840 // add new enchanting if equipped
3841 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3844 void Spell::EffectEnchantItemTmp(uint32 i)
3846 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3847 return;
3849 Player* p_caster = (Player*)m_caster;
3851 if(!itemTarget)
3852 return;
3854 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3856 // Shaman Rockbiter Weapon
3857 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3859 int32 enchnting_damage = m_currentBasePoints[1]+1;
3861 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3862 // with already applied percent bonus from Elemental Weapons talent
3863 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3864 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3865 switch(enchnting_damage)
3867 // Rank 1
3868 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3869 // Rank 2
3870 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3871 case 5: enchant_id = 3025; break; // 20%
3872 // Rank 3
3873 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3874 case 7: enchant_id = 3027; break; // 20%
3875 // Rank 4
3876 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3877 case 10: enchant_id = 503; break; // 14%
3878 case 11: enchant_id = 3031; break; // 20%
3879 // Rank 5
3880 case 15: enchant_id = 3035; break; // 0%
3881 case 16: enchant_id = 1663; break; // 7%
3882 case 17: enchant_id = 3033; break; // 14%
3883 case 18: enchant_id = 3034; break; // 20%
3884 // Rank 6
3885 case 28: enchant_id = 3038; break; // 0%
3886 case 29: enchant_id = 683; break; // 7%
3887 case 31: enchant_id = 3036; break; // 14%
3888 case 33: enchant_id = 3037; break; // 20%
3889 // Rank 7
3890 case 40: enchant_id = 3041; break; // 0%
3891 case 42: enchant_id = 1664; break; // 7%
3892 case 45: enchant_id = 3039; break; // 14%
3893 case 48: enchant_id = 3040; break; // 20%
3894 // Rank 8
3895 case 49: enchant_id = 3044; break; // 0%
3896 case 52: enchant_id = 2632; break; // 7%
3897 case 55: enchant_id = 3042; break; // 14%
3898 case 58: enchant_id = 3043; break; // 20%
3899 // Rank 9
3900 case 62: enchant_id = 2633; break; // 0%
3901 case 66: enchant_id = 3018; break; // 7%
3902 case 70: enchant_id = 3019; break; // 14%
3903 case 74: enchant_id = 3020; break; // 20%
3904 default:
3905 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3906 return;
3910 if (!enchant_id)
3912 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3913 return;
3916 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3917 if(!pEnchant)
3919 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3920 return;
3923 // select enchantment duration
3924 uint32 duration;
3926 // rogue family enchantments exception by duration
3927 if(m_spellInfo->Id==38615)
3928 duration = 1800; // 30 mins
3929 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3930 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3931 duration = 3600; // 1 hour
3932 // shaman family enchantments
3933 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3934 duration = 1800; // 30 mins
3935 // other cases with this SpellVisual already selected
3936 else if(m_spellInfo->SpellVisual[0]==215)
3937 duration = 1800; // 30 mins
3938 // some fishing pole bonuses
3939 else if(m_spellInfo->SpellVisual[0]==563)
3940 duration = 600; // 10 mins
3941 // shaman rockbiter enchantments
3942 else if(m_spellInfo->SpellVisual[0]==0)
3943 duration = 1800; // 30 mins
3944 else if(m_spellInfo->Id==29702)
3945 duration = 300; // 5 mins
3946 else if(m_spellInfo->Id==37360)
3947 duration = 300; // 5 mins
3948 // default case
3949 else
3950 duration = 3600; // 1 hour
3952 // item can be in trade slot and have owner diff. from caster
3953 Player* item_owner = itemTarget->GetOwner();
3954 if(!item_owner)
3955 return;
3957 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3959 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3960 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3961 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3962 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3965 // remove old enchanting before applying new if equipped
3966 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3968 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3970 // add new enchanting if equipped
3971 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3974 void Spell::EffectTameCreature(uint32 /*i*/)
3976 if(m_caster->GetPetGUID())
3977 return;
3979 if(!unitTarget)
3980 return;
3982 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3983 return;
3985 Creature* creatureTarget = (Creature*)unitTarget;
3987 if(creatureTarget->isPet())
3988 return;
3990 if(m_caster->getClass() != CLASS_HUNTER)
3991 return;
3993 // cast finish successfully
3994 //SendChannelUpdate(0);
3995 finish();
3997 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3999 // kill original creature
4000 creatureTarget->setDeathState(JUST_DIED);
4001 creatureTarget->RemoveCorpse();
4002 creatureTarget->SetHealth(0); // just for nice GM-mode view
4004 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4006 // prepare visual effect for levelup
4007 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4009 // add to world
4010 pet->GetMap()->Add((Creature*)pet);
4012 // visual effect for levelup
4013 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4015 // caster have pet now
4016 m_caster->SetPet(pet);
4018 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4020 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4021 ((Player*)m_caster)->PetSpellInitialize();
4025 void Spell::EffectSummonPet(uint32 i)
4027 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4029 Pet *OldSummon = m_caster->GetPet();
4031 // if pet requested type already exist
4032 if( OldSummon )
4034 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4036 // pet in corpse state can't be summoned
4037 if( OldSummon->isDead() )
4038 return;
4040 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4041 OldSummon->SetMapId(m_caster->GetMapId());
4043 float px, py, pz;
4044 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4046 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4047 m_caster->GetMap()->Add((Creature*)OldSummon);
4049 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4051 ((Player*)m_caster)->PetSpellInitialize();
4053 return;
4056 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4057 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4058 else
4059 return;
4062 Pet* NewSummon = new Pet;
4064 // petentry==0 for hunter "call pet" (current pet summoned if any)
4065 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4067 if(NewSummon->getPetType()==SUMMON_PET)
4069 // Remove Demonic Sacrifice auras (known pet)
4070 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4071 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4073 if((*itr)->GetModifier()->m_miscvalue==2228)
4075 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4076 itr = auraClassScripts.begin();
4078 else
4079 ++itr;
4083 return;
4086 // not error in case fail hunter call pet
4087 if(!petentry)
4089 delete NewSummon;
4090 return;
4093 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4095 if(!cInfo)
4097 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4098 delete NewSummon;
4099 return;
4102 Map *map = m_caster->GetMap();
4103 uint32 pet_number = objmgr.GeneratePetNumber();
4104 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4106 delete NewSummon;
4107 return;
4110 float px, py, pz;
4111 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4113 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4115 if(!NewSummon->IsPositionValid())
4117 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4118 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4119 delete NewSummon;
4120 return;
4123 uint32 petlevel = m_caster->getLevel();
4124 NewSummon->setPetType(SUMMON_PET);
4126 uint32 faction = m_caster->getFaction();
4127 if(m_caster->GetTypeId() == TYPEID_UNIT)
4129 if ( ((Creature*)m_caster)->isTotem() )
4130 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4131 else
4132 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4135 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4136 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4137 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4138 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4139 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4140 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4141 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4142 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4143 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4144 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4146 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4147 // this enables pet details window (Shift+P)
4149 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4150 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4151 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4153 NewSummon->InitStatsForLevel(petlevel);
4154 NewSummon->InitPetCreateSpells();
4155 NewSummon->InitTalentForLevel();
4157 if(NewSummon->getPetType()==SUMMON_PET)
4159 // Remove Demonic Sacrifice auras (new pet)
4160 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4161 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4163 if((*itr)->GetModifier()->m_miscvalue==2228)
4165 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4166 itr = auraClassScripts.begin();
4168 else
4169 ++itr;
4172 // generate new name for summon pet
4173 std::string new_name=objmgr.GeneratePetName(petentry);
4174 if(!new_name.empty())
4175 NewSummon->SetName(new_name);
4177 else if(NewSummon->getPetType()==HUNTER_PET)
4178 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4180 NewSummon->AIM_Initialize();
4181 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4182 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4184 map->Add((Creature*)NewSummon);
4186 m_caster->SetPet(NewSummon);
4187 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4189 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4191 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4192 ((Player*)m_caster)->PetSpellInitialize();
4196 void Spell::EffectLearnPetSpell(uint32 i)
4198 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4199 return;
4201 Player *_player = (Player*)m_caster;
4203 Pet *pet = _player->GetPet();
4204 if(!pet)
4205 return;
4206 if(!pet->isAlive())
4207 return;
4209 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4210 if(!learn_spellproto)
4211 return;
4213 pet->learnSpell(learn_spellproto->Id);
4215 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4216 _player->PetSpellInitialize();
4219 void Spell::EffectTaunt(uint32 /*i*/)
4221 // this effect use before aura Taunt apply for prevent taunt already attacking target
4222 // for spell as marked "non effective at already attacking target"
4223 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4225 if(unitTarget->getVictim()==m_caster)
4227 SendCastResult(SPELL_FAILED_DONT_REPORT);
4228 return;
4232 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4233 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4234 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4237 void Spell::EffectWeaponDmg(uint32 i)
4239 if(!unitTarget)
4240 return;
4241 if(!unitTarget->isAlive())
4242 return;
4244 // multiple weapon dmg effect workaround
4245 // execute only the last weapon damage
4246 // and handle all effects at once
4247 for (int j = 0; j < 3; j++)
4249 switch(m_spellInfo->Effect[j])
4251 case SPELL_EFFECT_WEAPON_DAMAGE:
4252 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4253 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4254 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4255 if (j < i) // we must calculate only at last weapon effect
4256 return;
4257 break;
4261 // some spell specific modifiers
4262 bool customBonusDamagePercentMod = false;
4263 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4264 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4265 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4266 bool normalized = false;
4268 int32 spell_bonus = 0; // bonus specific for spell
4269 switch(m_spellInfo->SpellFamilyName)
4271 case SPELLFAMILY_WARRIOR:
4273 // Whirlwind, single only spell with 2 weapon white damage apply if have
4274 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4276 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4277 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4279 // Devastate bonus and sunder armor refresh
4280 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4282 uint32 stack = 0;
4283 // Need refresh all Sunder Armor auras from this caster
4284 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4285 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4287 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4288 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4289 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4290 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4292 (*itr).second->RefreshAura();
4293 stack = (*itr).second->GetStackAmount();
4296 if (stack)
4297 spell_bonus += stack * CalculateDamage(2, unitTarget);
4299 break;
4301 case SPELLFAMILY_ROGUE:
4303 // Ambush
4304 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4306 customBonusDamagePercentMod = true;
4307 bonusDamagePercentMod = 2.5f; // 250%
4309 // Mutilate (for each hand)
4310 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4312 bool found = false;
4313 // fast check
4314 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4315 found = true;
4316 // full aura scan
4317 else
4319 Unit::AuraMap const& auras = unitTarget->GetAuras();
4320 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4322 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4324 found = true;
4325 break;
4330 if(found)
4331 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4333 break;
4335 case SPELLFAMILY_PALADIN:
4337 // Seal of Command - receive benefit from Spell Damage and Healing
4338 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4340 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4341 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4343 break;
4345 case SPELLFAMILY_SHAMAN:
4347 // Skyshatter Harness item set bonus
4348 // Stormstrike
4349 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4351 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4352 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4354 // Stormstrike AP Buff
4355 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4357 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4358 break;
4365 int32 fixed_bonus = 0;
4366 for (int j = 0; j < 3; j++)
4368 switch(m_spellInfo->Effect[j])
4370 case SPELL_EFFECT_WEAPON_DAMAGE:
4371 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4372 fixed_bonus += CalculateDamage(j,unitTarget);
4373 break;
4374 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4375 fixed_bonus += CalculateDamage(j,unitTarget);
4376 normalized = true;
4377 break;
4378 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4379 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4381 // applied only to prev.effects fixed damage
4382 if(customBonusDamagePercentMod)
4383 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4384 else
4385 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4386 break;
4387 default:
4388 break; // not weapon damage effect, just skip
4392 // non-weapon damage
4393 int32 bonus = spell_bonus + fixed_bonus;
4395 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4396 if(bonus)
4398 UnitMods unitMod;
4399 switch(m_attackType)
4401 default:
4402 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4403 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4404 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4407 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4408 bonus = int32(bonus*weapon_total_pct);
4411 // + weapon damage with applied weapon% dmg to base weapon damage in call
4412 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4414 // total damage
4415 bonus = int32(bonus*totalDamagePercentMod);
4417 // prevent negative damage
4418 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4420 // Add melee damage bonuses (also check for negative)
4421 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4422 m_damage+= eff_damage;
4424 // Hemorrhage
4425 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4427 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4428 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4431 // Mangle (Cat): CP
4432 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4434 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4435 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4438 // take ammo
4439 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4441 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4443 // wands don't have ammo
4444 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4445 return;
4447 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4449 if(pItem->GetMaxStackCount()==1)
4451 // decrease durability for non-stackable throw weapon
4452 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4454 else
4456 // decrease items amount for stackable throw weapon
4457 uint32 count = 1;
4458 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4461 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4462 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4466 void Spell::EffectThreat(uint32 /*i*/)
4468 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4469 return;
4471 if(!unitTarget->CanHaveThreatList())
4472 return;
4474 unitTarget->AddThreat(m_caster, float(damage));
4477 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4479 if(!unitTarget)
4480 return;
4481 if(!unitTarget->isAlive())
4482 return;
4484 uint32 heal = m_caster->GetMaxHealth();
4486 m_healing+=heal;
4489 void Spell::EffectInterruptCast(uint32 /*i*/)
4491 if(!unitTarget)
4492 return;
4493 if(!unitTarget->isAlive())
4494 return;
4496 // TODO: not all spells that used this effect apply cooldown at school spells
4497 // also exist case: apply cooldown to interrupted cast only and to all spells
4498 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4500 if (unitTarget->m_currentSpells[i])
4502 // check if we can interrupt spell
4503 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4505 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4506 unitTarget->InterruptSpell(i,false);
4512 void Spell::EffectSummonObjectWild(uint32 i)
4514 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4516 GameObject* pGameObj = new GameObject;
4518 WorldObject* target = focusObject;
4519 if( !target )
4520 target = m_caster;
4522 float x,y,z;
4523 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4525 x = m_targets.m_destX;
4526 y = m_targets.m_destY;
4527 z = m_targets.m_destZ;
4529 else
4530 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4532 Map *map = target->GetMap();
4534 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4535 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4537 delete pGameObj;
4538 return;
4541 int32 duration = GetSpellDuration(m_spellInfo);
4542 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4543 pGameObj->SetSpellId(m_spellInfo->Id);
4545 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4546 m_caster->AddGameObject(pGameObj);
4547 map->Add(pGameObj);
4549 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4551 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4553 Player *pl = (Player*)m_caster;
4554 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4555 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4557 uint32 team = ALLIANCE;
4559 if(pl->GetTeam() == team)
4560 team = HORDE;
4562 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4567 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4569 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4571 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4572 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4574 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4579 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4581 GameObject* linkedGO = new GameObject;
4582 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4583 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4585 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4586 linkedGO->SetSpellId(m_spellInfo->Id);
4588 m_caster->AddGameObject(linkedGO);
4589 map->Add(linkedGO);
4591 else
4593 delete linkedGO;
4594 linkedGO = NULL;
4595 return;
4600 void Spell::EffectScriptEffect(uint32 effIndex)
4602 // TODO: we must implement hunter pet summon at login there (spell 6962)
4604 switch(m_spellInfo->SpellFamilyName)
4606 case SPELLFAMILY_GENERIC:
4608 switch(m_spellInfo->Id)
4610 // PX-238 Winter Wondervolt TRAP
4611 case 26275:
4613 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4615 // check presence
4616 for(int j = 0; j < 4; ++j)
4617 if(unitTarget->HasAura(spells[j],0))
4618 return;
4620 // select spell
4621 uint32 iTmpSpellId = spells[urand(0,3)];
4623 // cast
4624 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4625 return;
4627 // Bending Shinbone
4628 case 8856:
4630 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4631 return;
4633 uint32 spell_id = 0;
4634 switch(urand(1,5))
4636 case 1: spell_id = 8854; break;
4637 default: spell_id = 8855; break;
4640 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4641 return;
4643 // Brittle Armor - need remove one 24575 Brittle Armor aura
4644 case 24590:
4645 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4646 return;
4647 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4648 case 26465:
4649 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4650 return;
4651 // Orb teleport spells
4652 case 25140:
4653 case 25143:
4654 case 25650:
4655 case 25652:
4656 case 29128:
4657 case 29129:
4658 case 35376:
4659 case 35727:
4661 if(!unitTarget)
4662 return;
4664 uint32 spellid;
4665 switch(m_spellInfo->Id)
4667 case 25140: spellid = 32571; break;
4668 case 25143: spellid = 32572; break;
4669 case 25650: spellid = 30140; break;
4670 case 25652: spellid = 30141; break;
4671 case 29128: spellid = 32568; break;
4672 case 29129: spellid = 32569; break;
4673 case 35376: spellid = 25649; break;
4674 case 35727: spellid = 35730; break;
4675 default:
4676 return;
4679 unitTarget->CastSpell(unitTarget,spellid,false);
4680 return;
4682 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4683 case 22539:
4684 case 22972:
4685 case 22975:
4686 case 22976:
4687 case 22977:
4688 case 22978:
4689 case 22979:
4690 case 22980:
4691 case 22981:
4692 case 22982:
4693 case 22983:
4694 case 22984:
4695 case 22985:
4697 if(!unitTarget || !unitTarget->isAlive())
4698 return;
4700 // Onyxia Scale Cloak
4701 if(unitTarget->GetDummyAura(22683))
4702 return;
4704 // Shadow Flame
4705 m_caster->CastSpell(unitTarget, 22682, true);
4706 return;
4708 // Summon Black Qiraji Battle Tank
4709 case 26656:
4711 if(!unitTarget)
4712 return;
4714 // Prevent stacking of mounts
4715 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4717 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4718 if (unitTarget->GetAreaId() == 3428)
4719 unitTarget->CastSpell(unitTarget, 25863, false);
4720 else
4721 unitTarget->CastSpell(unitTarget, 26655, false);
4722 break;
4724 // Piccolo of the Flaming Fire
4725 case 17512:
4727 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4728 return;
4729 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4730 break;
4732 // Mirren's Drinking Hat
4733 case 29830:
4735 uint32 item = 0;
4736 switch ( urand(1,6) )
4738 case 1:case 2:case 3:
4739 item = 23584;break; // Loch Modan Lager
4740 case 4:case 5:
4741 item = 23585;break; // Stouthammer Lite
4742 case 6:
4743 item = 23586;break; // Aerie Peak Pale Ale
4745 if (item)
4746 DoCreateItem(effIndex,item);
4747 break;
4749 // Improved Sprint
4750 case 30918:
4752 // Removes snares and roots.
4753 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4754 Unit::AuraMap& Auras = unitTarget->GetAuras();
4755 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4757 next = iter;
4758 ++next;
4759 Aura *aur = iter->second;
4760 if (!aur->IsPositive()) //only remove negative spells
4762 // check for mechanic mask
4763 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4765 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4766 if(Auras.empty())
4767 break;
4768 else
4769 next = Auras.begin();
4773 break;
4775 // Flame Crash
4776 case 41126:
4778 if(!unitTarget)
4779 return;
4781 unitTarget->CastSpell(unitTarget, 41131, true);
4782 break;
4784 // Force Cast - Portal Effect: Sunwell Isle
4785 case 44876:
4787 if(!unitTarget)
4788 return;
4790 unitTarget->CastSpell(unitTarget, 44870, true);
4791 break;
4793 // Goblin Weather Machine
4794 case 46203:
4796 if(!unitTarget)
4797 return;
4799 uint32 spellId;
4800 switch(rand()%4)
4802 case 0: spellId = 46740; break;
4803 case 1: spellId = 46739; break;
4804 case 2: spellId = 46738; break;
4805 case 3: spellId = 46736; break;
4807 unitTarget->CastSpell(unitTarget, spellId, true);
4808 break;
4810 //5,000 Gold
4811 case 46642:
4813 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4814 return;
4816 ((Player*)unitTarget)->ModifyMoney(50000000);
4818 break;
4820 // Emblazon Runeblade
4821 case 51770:
4823 if(!unitTarget)
4824 return;
4826 unitTarget->CastSpell(unitTarget,51771,false);
4827 break;
4829 // Death Gate
4830 case 52751:
4832 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4833 return;
4834 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4835 unitTarget->CastSpell(unitTarget, damage, false);
4836 break;
4838 // random spell learn instead placeholder
4839 case 60893: // Northrend Alchemy Research
4840 case 61177: // Northrend Inscription Research
4841 case 61288: // Minor Inscription Research
4842 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4844 if(!IsExplicitDiscoverySpell(m_spellInfo))
4846 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4847 return;
4850 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4851 return;
4852 Player* player = (Player*)m_caster;
4854 // need replace effect 0 item by loot
4855 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4857 if(!player->HasItemCount(reagent_id,1))
4858 return;
4860 // remove reagent
4861 uint32 count = 1;
4862 player->DestroyItemCount (reagent_id,count,true);
4864 // create some random items
4865 player->AutoStoreLootItem(m_spellInfo->Id,LootTemplates_Spell);
4867 // learn random explicit discovery recipe (if any)
4868 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4869 player->learnSpell(discoveredSpell);
4870 return;
4873 break;
4875 case SPELLFAMILY_WARLOCK:
4877 switch(m_spellInfo->Id)
4879 // Healthstone creating spells
4880 case 6201:
4881 case 6202:
4882 case 5699:
4883 case 11729:
4884 case 11730:
4885 case 27230:
4886 case 47871:
4887 case 47878:
4889 uint32 itemtype;
4890 uint32 rank = 0;
4891 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4892 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4894 if((*i)->GetId() == 18692)
4896 rank = 1;
4897 break;
4899 else if((*i)->GetId() == 18693)
4901 rank = 2;
4902 break;
4906 static uint32 const itypes[8][3] = {
4907 { 5512,19004,19005}, // Minor Healthstone
4908 { 5511,19006,19007}, // Lesser Healthstone
4909 { 5509,19008,19009}, // Healthstone
4910 { 5510,19010,19011}, // Greater Healthstone
4911 { 9421,19012,19013}, // Major Healthstone
4912 {22103,22104,22105}, // Master Healthstone
4913 {36889,36890,36891}, // Demonic Healthstone
4914 {36892,36893,36894} // Fel Healthstone
4917 switch(m_spellInfo->Id)
4919 case 6201:
4920 itemtype=itypes[0][rank];break; // Minor Healthstone
4921 case 6202:
4922 itemtype=itypes[1][rank];break; // Lesser Healthstone
4923 case 5699:
4924 itemtype=itypes[2][rank];break; // Healthstone
4925 case 11729:
4926 itemtype=itypes[3][rank];break; // Greater Healthstone
4927 case 11730:
4928 itemtype=itypes[4][rank];break; // Major Healthstone
4929 case 27230:
4930 itemtype=itypes[5][rank];break; // Master Healthstone
4931 case 47871:
4932 itemtype=itypes[6][rank];break; // Demonic Healthstone
4933 case 47878:
4934 itemtype=itypes[7][rank];break; // Fel Healthstone
4935 default:
4936 return;
4938 DoCreateItem( effIndex, itemtype );
4939 return;
4942 break;
4944 case SPELLFAMILY_HUNTER:
4946 switch(m_spellInfo->Id)
4948 // Chimera Shot
4949 case 53209:
4951 uint32 spellId = 0;
4952 int32 basePoint = 0;
4953 Unit::AuraMap& Auras = unitTarget->GetAuras();
4954 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
4956 Aura *aura = (*i).second;
4957 if (aura->GetCasterGUID() != m_caster->GetGUID())
4958 continue;
4959 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
4960 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
4961 if (!(familyFlag & 0x000000800000C000LL))
4962 continue;
4963 // Refresh aura duration
4964 aura->RefreshAura();
4966 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
4967 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
4969 spellId = 53353; // 53353 Chimera Shot - Serpent
4970 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
4972 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
4973 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
4975 spellId = 53358; // 53358 Chimera Shot - Viper
4976 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
4978 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
4979 if (familyFlag & 0x0000000000008000LL)
4980 spellId = 53359; // 53359 Chimera Shot - Scorpid
4981 // ?? nothing say in spell desc (possibly need addition check)
4982 //if (familyFlag & 0x0000010000000000LL || // dot
4983 // familyFlag & 0x0000100000000000LL) // stun
4985 // spellId = 53366; // 53366 Chimera Shot - Wyvern
4988 if (spellId)
4989 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
4990 return;
4992 default:
4993 break;
4995 break;
4997 case SPELLFAMILY_PALADIN:
4999 // Judgement
5000 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5002 if(!unitTarget || !unitTarget->isAlive())
5003 return;
5004 uint32 spellId1 = 0;
5005 uint32 spellId2 = 0;
5007 // Judgement self add switch
5008 switch (m_spellInfo->Id)
5010 case 41467: break; // Judgement
5011 case 53407: spellId1 = 20184; break; // Judgement of Justice
5012 case 20271: // Judgement of Light
5013 case 57774: spellId1 = 20185; break; // Judgement of Light
5014 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5015 default:
5016 return;
5018 // all seals have aura dummy in 2 effect
5019 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5020 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5022 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5023 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5024 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5025 continue;
5026 spellId2 = (*itr)->GetModifier()->m_amount;
5027 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5028 if (!judge)
5029 continue;
5030 break;
5032 if (spellId1)
5033 m_caster->CastSpell(unitTarget, spellId1, true);
5034 if (spellId2)
5035 m_caster->CastSpell(unitTarget, spellId2, true);
5036 return;
5039 case SPELLFAMILY_POTION:
5041 switch(m_spellInfo->Id)
5043 // Dreaming Glory
5044 case 28698:
5046 if(!unitTarget)
5047 return;
5048 unitTarget->CastSpell(unitTarget, 28694, true);
5049 break;
5051 // Netherbloom
5052 case 28702:
5054 if(!unitTarget)
5055 return;
5056 // 25% chance of casting a random buff
5057 if(roll_chance_i(75))
5058 return;
5060 // triggered spells are 28703 to 28707
5061 // Note: some sources say, that there was the possibility of
5062 // receiving a debuff. However, this seems to be removed by a patch.
5063 const uint32 spellid = 28703;
5065 // don't overwrite an existing aura
5066 for(uint8 i=0; i<5; i++)
5067 if(unitTarget->HasAura(spellid+i, 0))
5068 return;
5069 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5070 break;
5073 // Nightmare Vine
5074 case 28720:
5076 if(!unitTarget)
5077 return;
5078 // 25% chance of casting Nightmare Pollen
5079 if(roll_chance_i(75))
5080 return;
5081 unitTarget->CastSpell(unitTarget, 28721, true);
5082 break;
5085 break;
5089 // normal DB scripted effect
5090 if(!unitTarget)
5091 return;
5093 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5094 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5097 void Spell::EffectSanctuary(uint32 /*i*/)
5099 if(!unitTarget)
5100 return;
5101 //unitTarget->CombatStop();
5103 unitTarget->CombatStop();
5104 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5105 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5106 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5108 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5112 void Spell::EffectAddComboPoints(uint32 /*i*/)
5114 if(!unitTarget)
5115 return;
5117 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5118 return;
5120 if(damage <= 0)
5121 return;
5123 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5126 void Spell::EffectDuel(uint32 i)
5128 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5129 return;
5131 Player *caster = (Player*)m_caster;
5132 Player *target = (Player*)unitTarget;
5134 // caster or target already have requested duel
5135 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5136 return;
5138 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5139 // Don't have to check the target's map since you cannot challenge someone across maps
5140 uint32 mapid = caster->GetMapId();
5141 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5143 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5144 return;
5147 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5148 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5150 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5151 return;
5154 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5155 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5157 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5158 return;
5161 //CREATE DUEL FLAG OBJECT
5162 GameObject* pGameObj = new GameObject;
5164 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5166 Map *map = m_caster->GetMap();
5167 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
5168 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5169 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5170 m_caster->GetPositionZ(),
5171 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5173 delete pGameObj;
5174 return;
5177 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5178 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5179 int32 duration = GetSpellDuration(m_spellInfo);
5180 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5181 pGameObj->SetSpellId(m_spellInfo->Id);
5183 m_caster->AddGameObject(pGameObj);
5184 map->Add(pGameObj);
5185 //END
5187 // Send request
5188 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5189 data << pGameObj->GetGUID();
5190 data << caster->GetGUID();
5191 caster->GetSession()->SendPacket(&data);
5192 target->GetSession()->SendPacket(&data);
5194 // create duel-info
5195 DuelInfo *duel = new DuelInfo;
5196 duel->initiator = caster;
5197 duel->opponent = target;
5198 duel->startTime = 0;
5199 duel->startTimer = 0;
5200 caster->duel = duel;
5202 DuelInfo *duel2 = new DuelInfo;
5203 duel2->initiator = caster;
5204 duel2->opponent = caster;
5205 duel2->startTime = 0;
5206 duel2->startTimer = 0;
5207 target->duel = duel2;
5209 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5210 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5213 void Spell::EffectStuck(uint32 /*i*/)
5215 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5216 return;
5218 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5219 return;
5221 Player* pTarget = (Player*)unitTarget;
5223 sLog.outDebug("Spell Effect: Stuck");
5224 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());
5226 if(pTarget->isInFlight())
5227 return;
5229 // homebind location is loaded always
5230 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5232 // Stuck spell trigger Hearthstone cooldown
5233 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5234 if(!spellInfo)
5235 return;
5236 Spell spell(pTarget,spellInfo,true,0);
5237 spell.SendSpellCooldown();
5240 void Spell::EffectSummonPlayer(uint32 /*i*/)
5242 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5243 return;
5245 // Evil Twin (ignore player summon, but hide this for summoner)
5246 if(unitTarget->GetDummyAura(23445))
5247 return;
5249 float x,y,z;
5250 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5252 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5254 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5255 data << uint64(m_caster->GetGUID()); // summoner guid
5256 data << uint32(m_caster->GetZoneId()); // summoner zone
5257 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5258 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5261 static ScriptInfo generateActivateCommand()
5263 ScriptInfo si;
5264 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5265 return si;
5268 void Spell::EffectActivateObject(uint32 effect_idx)
5270 if(!gameObjTarget)
5271 return;
5273 static ScriptInfo activateCommand = generateActivateCommand();
5275 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5277 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5280 void Spell::EffectApplyGlyph(uint32 i)
5282 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5283 return;
5285 Player *player = (Player*)m_caster;
5287 // remove old glyph
5288 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5290 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5292 player->RemoveAurasDueToSpell(old_gp->SpellId);
5293 player->SetGlyph(m_glyphIndex, 0);
5297 // apply new one
5298 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5300 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5302 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5304 if(gp->TypeFlags != gs->TypeFlags)
5306 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5307 return; // glyph slot missmatch
5311 player->CastSpell(m_caster, gp->SpellId, true);
5312 player->SetGlyph(m_glyphIndex, glyph);
5317 void Spell::EffectSummonTotem(uint32 i)
5319 uint8 slot = 0;
5320 switch(m_spellInfo->EffectMiscValueB[i])
5322 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5323 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5324 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5325 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5326 // Battle standard case
5327 case SUMMON_TYPE_TOTEM: slot = 254; break;
5328 // jewelery statue case, like totem without slot
5329 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5330 default: return;
5333 if(slot < MAX_TOTEM)
5335 uint64 guid = m_caster->m_TotemSlot[slot];
5336 if(guid != 0)
5338 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5339 if(OldTotem && OldTotem->isTotem())
5340 ((Totem*)OldTotem)->UnSummon();
5344 uint32 team = 0;
5345 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5346 team = ((Player*)m_caster)->GetTeam();
5348 Totem* pTotem = new Totem;
5350 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5352 delete pTotem;
5353 return;
5356 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5358 float x,y,z;
5359 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5361 // totem must be at same Z in case swimming caster and etc.
5362 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5363 z = m_caster->GetPositionZ();
5365 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5367 if(slot < MAX_TOTEM)
5368 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5370 pTotem->SetOwner(m_caster->GetGUID());
5371 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5373 int32 duration=GetSpellDuration(m_spellInfo);
5374 if(Player* modOwner = m_caster->GetSpellModOwner())
5375 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5376 pTotem->SetDuration(duration);
5378 if (damage) // if not spell info, DB values used
5380 pTotem->SetMaxHealth(damage);
5381 pTotem->SetHealth(damage);
5384 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5386 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5387 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5389 pTotem->Summon(m_caster);
5391 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5393 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5394 data << uint8(slot);
5395 data << uint64(pTotem->GetGUID());
5396 data << uint32(duration);
5397 data << uint32(m_spellInfo->Id);
5398 ((Player*)m_caster)->SendDirectMessage(&data);
5402 void Spell::EffectEnchantHeldItem(uint32 i)
5404 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5405 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5406 return;
5408 Player* item_owner = (Player*)unitTarget;
5409 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5411 if(!item )
5412 return;
5414 // must be equipped
5415 if(!item ->IsEquipped())
5416 return;
5418 if (m_spellInfo->EffectMiscValue[i])
5420 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5421 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5422 if(!duration)
5423 duration = m_currentBasePoints[i]+1; //Base points after ..
5424 if(!duration)
5425 duration = 10; //10 seconds for enchants which don't have listed duration
5427 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5428 if(!pEnchant)
5429 return;
5431 // Always go to temp enchantment slot
5432 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5434 // Enchantment will not be applied if a different one already exists
5435 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5436 return;
5438 // Apply the temporary enchantment
5439 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5440 item_owner->ApplyEnchantment(item,slot,true);
5444 void Spell::EffectDisEnchant(uint32 /*i*/)
5446 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5447 return;
5449 Player* p_caster = (Player*)m_caster;
5450 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5451 return;
5453 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5455 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5457 // item will be removed at disenchanting end
5460 void Spell::EffectInebriate(uint32 /*i*/)
5462 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5463 return;
5465 Player *player = (Player*)unitTarget;
5466 uint16 currentDrunk = player->GetDrunkValue();
5467 uint16 drunkMod = damage * 256;
5468 if (currentDrunk + drunkMod > 0xFFFF)
5469 currentDrunk = 0xFFFF;
5470 else
5471 currentDrunk += drunkMod;
5472 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5475 void Spell::EffectFeedPet(uint32 i)
5477 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5478 return;
5480 Player *_player = (Player*)m_caster;
5482 Item* foodItem = m_targets.getItemTarget();
5483 if(!foodItem)
5484 return;
5486 Pet *pet = _player->GetPet();
5487 if(!pet)
5488 return;
5490 if(!pet->isAlive())
5491 return;
5493 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5494 if(benefit <= 0)
5495 return;
5497 uint32 count = 1;
5498 _player->DestroyItemCount(foodItem,count,true);
5499 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5501 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5504 void Spell::EffectDismissPet(uint32 /*i*/)
5506 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5507 return;
5509 Pet* pet = m_caster->GetPet();
5511 // not let dismiss dead pet
5512 if(!pet||!pet->isAlive())
5513 return;
5515 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5518 void Spell::EffectSummonObject(uint32 i)
5520 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5522 uint8 slot = 0;
5523 switch(m_spellInfo->Effect[i])
5525 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5526 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5527 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5528 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5529 default: return;
5532 uint64 guid = m_caster->m_ObjectSlot[slot];
5533 if(guid != 0)
5535 GameObject* obj = NULL;
5536 if( m_caster )
5537 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5539 if(obj) obj->Delete();
5540 m_caster->m_ObjectSlot[slot] = 0;
5543 GameObject* pGameObj = new GameObject;
5545 float rot2 = sin(m_caster->GetOrientation()/2);
5546 float rot3 = cos(m_caster->GetOrientation()/2);
5548 float x,y,z;
5549 // If dest location if present
5550 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5552 x = m_targets.m_destX;
5553 y = m_targets.m_destY;
5554 z = m_targets.m_destZ;
5556 // Summon in random point all other units if location present
5557 else
5558 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5560 Map *map = m_caster->GetMap();
5561 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5563 delete pGameObj;
5564 return;
5567 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5568 int32 duration = GetSpellDuration(m_spellInfo);
5569 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5570 pGameObj->SetSpellId(m_spellInfo->Id);
5571 m_caster->AddGameObject(pGameObj);
5573 map->Add(pGameObj);
5574 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5575 data << pGameObj->GetGUID();
5576 m_caster->SendMessageToSet(&data,true);
5578 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5581 void Spell::EffectResurrect(uint32 /*effIndex*/)
5583 if(!unitTarget)
5584 return;
5585 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5586 return;
5588 if(unitTarget->isAlive())
5589 return;
5590 if(!unitTarget->IsInWorld())
5591 return;
5593 switch (m_spellInfo->Id)
5595 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5596 case 8342:
5597 if (roll_chance_i(67))
5599 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5600 return;
5602 break;
5603 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5604 case 22999:
5605 if (roll_chance_i(50))
5607 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5608 return;
5610 break;
5611 default:
5612 break;
5615 Player* pTarget = ((Player*)unitTarget);
5617 if(pTarget->isRessurectRequested()) // already have one active request
5618 return;
5620 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5621 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5623 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5624 SendResurrectRequest(pTarget);
5627 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5629 if(!unitTarget || !unitTarget->isAlive())
5630 return;
5632 if( unitTarget->m_extraAttacks )
5633 return;
5635 unitTarget->m_extraAttacks = damage;
5638 void Spell::EffectParry(uint32 /*i*/)
5640 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5641 ((Player*)unitTarget)->SetCanParry(true);
5644 void Spell::EffectBlock(uint32 /*i*/)
5646 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5647 ((Player*)unitTarget)->SetCanBlock(true);
5650 void Spell::EffectMomentMove(uint32 i)
5652 if(unitTarget->isInFlight())
5653 return;
5655 if( m_spellInfo->rangeIndex== 1) //self range
5657 uint32 mapid = m_caster->GetMapId();
5658 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5660 // before caster
5661 float fx,fy,fz;
5662 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5663 float ox,oy,oz;
5664 unitTarget->GetPosition(ox,oy,oz);
5666 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5667 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5669 fx = fx2;
5670 fy = fy2;
5671 fz = fz2;
5672 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5675 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5676 ((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));
5677 else
5678 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5682 void Spell::EffectReputation(uint32 i)
5684 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5685 return;
5687 Player *_player = (Player*)unitTarget;
5689 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5691 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5693 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5695 if(!factionEntry)
5696 return;
5698 _player->ModifyFactionReputation(factionEntry,rep_change);
5701 void Spell::EffectQuestComplete(uint32 i)
5703 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5704 return;
5706 Player *_player = (Player*)m_caster;
5708 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5709 _player->AreaExploredOrEventHappens(quest_id);
5712 void Spell::EffectSelfResurrect(uint32 i)
5714 if(!unitTarget || unitTarget->isAlive())
5715 return;
5716 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5717 return;
5718 if(!unitTarget->IsInWorld())
5719 return;
5721 uint32 health = 0;
5722 uint32 mana = 0;
5724 // flat case
5725 if(damage < 0)
5727 health = uint32(-damage);
5728 mana = m_spellInfo->EffectMiscValue[i];
5730 // percent case
5731 else
5733 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5734 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5735 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5738 Player *plr = ((Player*)unitTarget);
5739 plr->ResurrectPlayer(0.0f);
5741 plr->SetHealth( health );
5742 plr->SetPower(POWER_MANA, mana );
5743 plr->SetPower(POWER_RAGE, 0 );
5744 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5746 plr->SpawnCorpseBones();
5748 plr->SaveToDB();
5751 void Spell::EffectSkinning(uint32 /*i*/)
5753 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5754 return;
5755 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5756 return;
5758 Creature* creature = (Creature*) unitTarget;
5759 int32 targetLevel = creature->getLevel();
5761 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5763 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5764 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5766 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5768 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5770 // Double chances for elites
5771 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5774 void Spell::EffectCharge(uint32 /*i*/)
5776 if(!unitTarget || !m_caster)
5777 return;
5779 float x, y, z;
5780 unitTarget->GetContactPoint(m_caster, x, y, z);
5781 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5782 ((Creature *)unitTarget)->StopMoving();
5784 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5785 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5787 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5788 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5790 // not all charge effects used in negative spells
5791 if ( !IsPositiveSpell(m_spellInfo->Id))
5792 m_caster->Attack(unitTarget,true);
5795 void Spell::EffectSummonCritter(uint32 i)
5797 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5798 return;
5799 Player* player = (Player*)m_caster;
5801 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5802 if(!pet_entry)
5803 return;
5805 Pet* old_critter = player->GetMiniPet();
5807 // for same pet just despawn
5808 if(old_critter && old_critter->GetEntry() == pet_entry)
5810 player->RemoveMiniPet();
5811 return;
5814 // despawn old pet before summon new
5815 if(old_critter)
5816 player->RemoveMiniPet();
5818 // summon new pet
5819 Pet* critter = new Pet(MINI_PET);
5821 Map *map = m_caster->GetMap();
5822 uint32 pet_number = objmgr.GeneratePetNumber();
5823 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5824 map, pet_entry, pet_number))
5826 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5827 delete critter;
5828 return;
5831 float x,y,z;
5832 // If dest location if present
5833 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5835 x = m_targets.m_destX;
5836 y = m_targets.m_destY;
5837 z = m_targets.m_destZ;
5839 // Summon if dest location not present near caster
5840 else
5841 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5843 critter->Relocate(x,y,z,m_caster->GetOrientation());
5845 if(!critter->IsPositionValid())
5847 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5848 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5849 delete critter;
5850 return;
5853 critter->SetOwnerGUID(m_caster->GetGUID());
5854 critter->SetCreatorGUID(m_caster->GetGUID());
5855 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5856 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5858 critter->AIM_Initialize();
5859 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5860 critter->SetMaxHealth(1);
5861 critter->SetHealth(1);
5862 critter->SetLevel(1);
5864 // set timer for unsummon
5865 int32 duration = GetSpellDuration(m_spellInfo);
5866 if(duration > 0)
5867 critter->SetDuration(duration);
5869 std::string name = player->GetName();
5870 name.append(petTypeSuffix[critter->getPetType()]);
5871 critter->SetName( name );
5872 player->SetMiniPet(critter);
5874 map->Add((Creature*)critter);
5877 void Spell::EffectKnockBack(uint32 i)
5879 if(!unitTarget || !m_caster)
5880 return;
5882 // Effect only works on players
5883 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5884 return;
5886 float vsin = sin(m_caster->GetAngle(unitTarget));
5887 float vcos = cos(m_caster->GetAngle(unitTarget));
5889 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5890 data.append(unitTarget->GetPackGUID());
5891 data << uint32(0); // Sequence
5892 data << float(vcos); // x direction
5893 data << float(vsin); // y direction
5894 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5895 data << float(damage/-10); // Z Movement speed (vertical)
5897 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5900 void Spell::EffectSendTaxi(uint32 i)
5902 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5903 return;
5905 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5906 if(!entry)
5907 return;
5909 std::vector<uint32> nodes;
5911 nodes.resize(2);
5912 nodes[0] = entry->from;
5913 nodes[1] = entry->to;
5915 uint32 mountid = 0;
5916 switch(m_spellInfo->Id)
5918 case 31606: //Stormcrow Amulet
5919 mountid = 17447;
5920 break;
5921 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5922 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5923 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5924 mountid = 22840;
5925 break;
5926 case 34905: //Stealth Flight
5927 mountid = 6851;
5928 break;
5929 case 45883: //Amber Ledge to Beryl Point
5930 mountid = 23524;
5931 break;
5932 case 46064: //Amber Ledge to Coldarra
5933 mountid = 6371;
5934 break;
5935 case 53335: //Stormwind Harbor Flight - Peaceful
5936 mountid = 6852;
5937 break;
5940 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5944 void Spell::EffectPlayerPull(uint32 i)
5946 if(!unitTarget || !m_caster)
5947 return;
5949 // Effect only works on players
5950 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5951 return;
5953 float vsin = sin(unitTarget->GetAngle(m_caster));
5954 float vcos = cos(unitTarget->GetAngle(m_caster));
5956 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5957 data.append(unitTarget->GetPackGUID());
5958 data << uint32(0); // Sequence
5959 data << float(vcos); // x direction
5960 data << float(vsin); // y direction
5961 // Horizontal speed
5962 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5963 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5965 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5968 void Spell::EffectDispelMechanic(uint32 i)
5970 if(!unitTarget)
5971 return;
5973 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5975 Unit::AuraMap& Auras = unitTarget->GetAuras();
5976 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5978 next = iter;
5979 ++next;
5980 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5981 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5983 unitTarget->RemoveAurasDueToSpell(spell->Id);
5984 if(Auras.empty())
5985 break;
5986 else
5987 next = Auras.begin();
5990 return;
5993 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5995 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5996 return;
5997 Player *_player = (Player*)m_caster;
5998 Pet *pet = _player->GetPet();
5999 if(!pet)
6000 return;
6001 if(pet->isAlive())
6002 return;
6003 if(damage < 0)
6004 return;
6005 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6006 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6007 pet->setDeathState( ALIVE );
6008 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6009 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6011 pet->AIM_Initialize();
6013 _player->PetSpellInitialize();
6014 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6017 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6019 float mana = 0;
6020 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6022 if(!m_caster->m_TotemSlot[slot])
6023 continue;
6025 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
6026 if(totem && totem->isTotem())
6028 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6029 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6030 if(spellInfo)
6031 mana += spellInfo->manaCost * damage / 100;
6032 ((Totem*)totem)->UnSummon();
6036 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
6037 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
6040 void Spell::EffectDurabilityDamage(uint32 i)
6042 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6043 return;
6045 int32 slot = m_spellInfo->EffectMiscValue[i];
6047 // FIXME: some spells effects have value -1/-2
6048 // Possibly its mean -1 all player equipped items and -2 all items
6049 if(slot < 0)
6051 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6052 return;
6055 // invalid slot value
6056 if(slot >= INVENTORY_SLOT_BAG_END)
6057 return;
6059 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6060 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6063 void Spell::EffectDurabilityDamagePCT(uint32 i)
6065 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6066 return;
6068 int32 slot = m_spellInfo->EffectMiscValue[i];
6070 // FIXME: some spells effects have value -1/-2
6071 // Possibly its mean -1 all player equipped items and -2 all items
6072 if(slot < 0)
6074 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6075 return;
6078 // invalid slot value
6079 if(slot >= INVENTORY_SLOT_BAG_END)
6080 return;
6082 if(damage <= 0)
6083 return;
6085 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6086 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6089 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6091 if(!unitTarget)
6092 return;
6094 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6097 void Spell::EffectTransmitted(uint32 effIndex)
6099 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6101 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6103 if (!goinfo)
6105 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6106 return;
6109 float fx,fy,fz;
6111 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6113 fx = m_targets.m_destX;
6114 fy = m_targets.m_destY;
6115 fz = m_targets.m_destZ;
6117 //FIXME: this can be better check for most objects but still hack
6118 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6120 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6121 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6123 else
6125 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6126 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6127 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6129 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6132 Map *cMap = m_caster->GetMap();
6134 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6136 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6137 { // but this is not proper, we really need to ignore not materialized objects
6138 SendCastResult(SPELL_FAILED_NOT_HERE);
6139 SendChannelUpdate(0);
6140 return;
6143 // replace by water level in this case
6144 fz = cMap->GetWaterLevel(fx,fy);
6146 // if gameobject is summoning object, it should be spawned right on caster's position
6147 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6149 m_caster->GetPosition(fx,fy,fz);
6152 GameObject* pGameObj = new GameObject;
6154 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6155 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6157 delete pGameObj;
6158 return;
6161 int32 duration = GetSpellDuration(m_spellInfo);
6163 switch(goinfo->type)
6165 case GAMEOBJECT_TYPE_FISHINGNODE:
6167 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6168 // Orientation3
6169 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6170 // Orientation4
6171 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6172 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6174 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6175 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6176 int32 lastSec;
6177 switch(urand(0, 3))
6179 case 0: lastSec = 3; break;
6180 case 1: lastSec = 7; break;
6181 case 2: lastSec = 13; break;
6182 case 3: lastSec = 17; break;
6185 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6186 break;
6188 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6190 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6192 pGameObj->AddUniqueUse((Player*)m_caster);
6193 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6195 break;
6197 case GAMEOBJECT_TYPE_FISHINGHOLE:
6198 case GAMEOBJECT_TYPE_CHEST:
6199 default:
6201 break;
6205 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6207 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6209 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6210 pGameObj->SetSpellId(m_spellInfo->Id);
6212 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6213 //m_caster->AddGameObject(pGameObj);
6214 //m_ObjToDel.push_back(pGameObj);
6216 cMap->Add(pGameObj);
6218 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6219 data << uint64(pGameObj->GetGUID());
6220 m_caster->SendMessageToSet(&data,true);
6222 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6224 GameObject* linkedGO = new GameObject;
6225 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6226 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6228 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6229 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6230 linkedGO->SetSpellId(m_spellInfo->Id);
6231 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6233 linkedGO->GetMap()->Add(linkedGO);
6235 else
6237 delete linkedGO;
6238 linkedGO = NULL;
6239 return;
6244 void Spell::EffectProspecting(uint32 /*i*/)
6246 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6247 return;
6249 Player* p_caster = (Player*)m_caster;
6250 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6251 return;
6253 if(itemTarget->GetCount() < 5)
6254 return;
6256 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6258 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6259 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6260 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6263 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6266 void Spell::EffectMilling(uint32 /*i*/)
6268 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6269 return;
6271 Player* p_caster = (Player*)m_caster;
6272 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6273 return;
6275 if(itemTarget->GetCount() < 5)
6276 return;
6278 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6280 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6281 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6282 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6285 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6288 void Spell::EffectSkill(uint32 /*i*/)
6290 sLog.outDebug("WORLD: SkillEFFECT");
6293 void Spell::EffectSummonDemon(uint32 i)
6295 float px = m_targets.m_destX;
6296 float py = m_targets.m_destY;
6297 float pz = m_targets.m_destZ;
6299 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6300 if (!Charmed)
6301 return;
6303 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6304 Charmed->SetLevel(m_caster->getLevel());
6306 // TODO: Add damage/mana/hp according to level
6308 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6310 // Enslave demon effect, without mana cost and cooldown
6311 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6313 // Inferno effect
6314 Charmed->CastSpell(Charmed, 22703, true, 0);
6318 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6319 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6320 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6321 This is why we use a half sec delay between the visual effect and the resurrection itself */
6322 void Spell::EffectSpiritHeal(uint32 /*i*/)
6325 if(!unitTarget || unitTarget->isAlive())
6326 return;
6327 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6328 return;
6329 if(!unitTarget->IsInWorld())
6330 return;
6332 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6333 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6334 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6335 ((Player*)unitTarget)->SpawnCorpseBones();
6339 // remove insignia spell effect
6340 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6342 sLog.outDebug("Effect: SkinPlayerCorpse");
6343 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6344 return;
6346 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6349 void Spell::EffectStealBeneficialBuff(uint32 i)
6351 sLog.outDebug("Effect: StealBeneficialBuff");
6353 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6354 return;
6356 std::vector <Aura *> steal_list;
6357 // Create dispel mask by dispel type
6358 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6359 Unit::AuraMap const& auras = unitTarget->GetAuras();
6360 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6362 Aura *aur = (*itr).second;
6363 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6365 // Need check for passive? this
6366 if (aur->IsPositive() && !aur->IsPassive())
6367 steal_list.push_back(aur);
6370 // Ok if exist some buffs for dispel try dispel it
6371 if (!steal_list.empty())
6373 std::list < std::pair<uint32,uint64> > success_list;
6374 int32 list_size = steal_list.size();
6375 // Dispell N = damage buffs (or while exist buffs for dispel)
6376 for (int32 count=0; count < damage && list_size > 0; ++count)
6378 // Random select buff for dispel
6379 Aura *aur = steal_list[urand(0, list_size-1)];
6380 // Not use chance for steal
6381 // TODO possible need do it
6382 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6384 // Remove buff from list for prevent doubles
6385 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6387 Aura *stealed = *j;
6388 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6390 j = steal_list.erase(j);
6391 --list_size;
6393 else
6394 ++j;
6397 // Really try steal and send log
6398 if (!success_list.empty())
6400 int32 count = success_list.size();
6401 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6402 data.append(unitTarget->GetPackGUID()); // Victim GUID
6403 data.append(m_caster->GetPackGUID()); // Caster GUID
6404 data << uint32(m_spellInfo->Id); // Dispell spell id
6405 data << uint8(0); // not used
6406 data << uint32(count); // count
6407 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6409 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6410 data << uint32(spellInfo->Id); // Spell Id
6411 data << uint8(0); // 0 - steals !=0 transfers
6412 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6414 m_caster->SendMessageToSet(&data, true);
6419 void Spell::EffectKillCredit(uint32 i)
6421 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6422 return;
6424 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6427 void Spell::EffectQuestFail(uint32 i)
6429 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6430 return;
6432 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6435 void Spell::EffectActivateRune(uint32 eff_idx)
6437 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6438 return;
6440 Player *plr = (Player*)m_caster;
6442 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6443 return;
6445 for(uint32 j = 0; j < MAX_RUNES; ++j)
6447 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6449 plr->SetRuneCooldown(j, 0);
6454 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6456 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6457 ((Player*)unitTarget)->SetCanTitanGrip(true);
6460 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6462 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6463 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6464 return;
6466 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);