[7801] Apply damage mods from scripts or target state not in DealDamage but in new...
[getmangos.git] / src / game / SpellEffects.cpp
blobba57067b879f16afac90d45311645d8b059cfbb3
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 "Database/DatabaseEnv.h"
21 #include "WorldPacket.h"
22 #include "Opcodes.h"
23 #include "Log.h"
24 #include "UpdateMask.h"
25 #include "World.h"
26 #include "ObjectMgr.h"
27 #include "SpellMgr.h"
28 #include "Player.h"
29 #include "SkillExtraItems.h"
30 #include "Unit.h"
31 #include "Spell.h"
32 #include "DynamicObject.h"
33 #include "SpellAuras.h"
34 #include "Group.h"
35 #include "UpdateData.h"
36 #include "MapManager.h"
37 #include "ObjectAccessor.h"
38 #include "SharedDefines.h"
39 #include "Pet.h"
40 #include "GameObject.h"
41 #include "GossipDef.h"
42 #include "Creature.h"
43 #include "Totem.h"
44 #include "CreatureAI.h"
45 #include "BattleGroundMgr.h"
46 #include "BattleGround.h"
47 #include "BattleGroundEY.h"
48 #include "BattleGroundWS.h"
49 #include "VMapFactory.h"
50 #include "Language.h"
51 #include "SocialMgr.h"
52 #include "Util.h"
53 #include "TemporarySummon.h"
54 #include "ScriptCalls.h"
55 #include "SkillDiscovery.h"
56 #include "Formulas.h"
58 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
60 &Spell::EffectNULL, // 0
61 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP
102 &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
103 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
107 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
120 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
126 &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
127 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
134 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
135 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectUnused, // 87 SPELL_EFFECT_WMO_DAMAGE
148 &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
149 &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
150 &Spell::EffectUnused, // 90 SPELL_EFFECT_KILL_CREDIT
151 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
154 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectUnused, // 97 SPELL_EFFECT_97
158 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
170 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectUnused, //112 SPELL_EFFECT_112
173 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
185 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
192 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
193 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
199 &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
200 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
202 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
205 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
206 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
207 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
209 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
210 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
211 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
213 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
214 &Spell::EffectNULL, //154 unused
215 &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
216 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
217 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
218 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
219 &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
222 void Spell::EffectNULL(uint32 /*i*/)
224 sLog.outDebug("WORLD: Spell Effect DUMMY");
227 void Spell::EffectUnused(uint32 /*i*/)
229 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
232 void Spell::EffectResurrectNew(uint32 i)
234 if(!unitTarget || unitTarget->isAlive())
235 return;
237 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
238 return;
240 if(!unitTarget->IsInWorld())
241 return;
243 Player* pTarget = ((Player*)unitTarget);
245 if(pTarget->isRessurectRequested()) // already have one active request
246 return;
248 uint32 health = damage;
249 uint32 mana = m_spellInfo->EffectMiscValue[i];
250 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
251 SendResurrectRequest(pTarget);
254 void Spell::EffectInstaKill(uint32 /*i*/)
256 if( !unitTarget || !unitTarget->isAlive() )
257 return;
259 // Demonic Sacrifice
260 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
262 uint32 entry = unitTarget->GetEntry();
263 uint32 spellID;
264 switch(entry)
266 case 416: spellID=18789; break; //imp
267 case 417: spellID=18792; break; //fellhunter
268 case 1860: spellID=18790; break; //void
269 case 1863: spellID=18791; break; //succubus
270 case 17252: spellID=35701; break; //fellguard
271 default:
272 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
273 return;
276 m_caster->CastSpell(m_caster,spellID,true);
279 if(m_caster==unitTarget) // prevent interrupt message
280 finish();
282 m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
285 void Spell::EffectEnvirinmentalDMG(uint32 i)
287 uint32 absorb = 0;
288 uint32 resist = 0;
290 // Note: this hack with damage replace required until GO casting not implemented
291 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
292 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
293 damage = m_spellInfo->CalculateSimpleValue(i);
295 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
297 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
298 if(m_caster->GetTypeId() == TYPEID_PLAYER)
299 ((Player*)m_caster)->EnvironmentalDamage(DAMAGE_FIRE,damage);
302 void Spell::EffectSchoolDMG(uint32 effect_idx)
304 if( unitTarget && unitTarget->isAlive())
306 switch(m_spellInfo->SpellFamilyName)
308 case SPELLFAMILY_GENERIC:
310 //Gore
311 if(m_spellInfo->SpellIconID == 2269 )
313 damage+= rand()%2 ? damage : 0;
316 switch(m_spellInfo->Id) // better way to check unknown
318 // Meteor like spells (divided damage to targets)
319 case 24340: case 26558: case 28884: // Meteor
320 case 36837: case 38903: case 41276: // Meteor
321 case 26789: // Shard of the Fallen Star
322 case 31436: // Malevolent Cleave
323 case 35181: // Dive Bomb
324 case 40810: case 43267: case 43268: // Saber Lash
325 case 42384: // Brutal Swipe
326 case 45150: // Meteor Slash
328 uint32 count = 0;
329 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
330 if(ihit->effectMask & (1<<effect_idx))
331 ++count;
333 damage /= count; // divide to all targets
334 break;
336 // percent from health with min
337 case 25599: // Thundercrash
339 damage = unitTarget->GetHealth() / 2;
340 if(damage < 200)
341 damage = 200;
342 break;
344 // Intercept (warrior spell trigger)
345 case 20253:
346 case 61491:
348 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
349 break;
351 // Cataclysmic Bolt
352 case 38441:
353 damage = unitTarget->GetMaxHealth() / 2;
354 break;
356 break;
359 case SPELLFAMILY_MAGE:
361 // Arcane Blast
362 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
364 m_caster->CastSpell(m_caster,36032,true);
366 break;
368 case SPELLFAMILY_WARRIOR:
370 // Bloodthirst
371 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
373 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
375 // Shield Slam
376 else if(m_spellInfo->SpellFamilyFlags & 0x0000020000000000LL && m_spellInfo->Category==1209)
377 damage += int32(m_caster->GetShieldBlockValue());
378 // Victory Rush
379 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
381 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
382 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
384 // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
385 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000400LL)
386 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
387 // Heroic Throw ${$m1+$AP*.50}
388 else if(m_spellInfo->SpellFamilyFlags & 0x0000000100000000LL)
389 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
390 // Shockwave ${$m3/100*$AP}
391 else if(m_spellInfo->SpellFamilyFlags & 0x0000800000000000LL)
393 int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
394 if (pct > 0)
395 damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
396 break;
398 break;
400 case SPELLFAMILY_WARLOCK:
402 // Incinerate Rank 1 & 2
403 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
405 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
406 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
407 damage += int32(damage*0.25f);
409 break;
411 case SPELLFAMILY_PRIEST:
413 // Shadow Word: Death - deals damage equal to damage done to caster
414 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
415 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
416 break;
418 case SPELLFAMILY_DRUID:
420 // Ferocious Bite
421 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
423 // converts each extra point of energy into ($f1+$AP/410) additional damage
424 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
425 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
426 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
427 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
428 m_caster->SetPower(POWER_ENERGY,0);
430 // Rake
431 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
433 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
435 // Swipe
436 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
438 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
440 //Mangle Bonus for the initial damage of Lacerate and Rake
441 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
442 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
444 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
445 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
446 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
448 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
449 break;
452 break;
454 case SPELLFAMILY_ROGUE:
456 // Envenom
457 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
459 // consume from stack dozes not more that have combo-points
460 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
462 Aura *poison = 0;
463 // Lookup for Deadly poison (only attacker applied)
464 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
465 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
466 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
467 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
468 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
470 poison = *itr;
471 break;
473 // count consumed deadly poison doses at target
474 if (poison)
476 uint32 spellId = poison->GetId();
477 uint32 doses = poison->GetStackAmount();
478 if (doses > combo)
479 doses = combo;
480 for (int i=0; i< doses; i++)
481 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
482 damage *= doses;
483 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
485 // Eviscerate and Envenom Bonus Damage (item set effect)
486 if(m_caster->GetDummyAura(37169))
487 damage += ((Player*)m_caster)->GetComboPoints()*40;
490 // Eviscerate
491 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
493 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
495 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
496 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
498 // Eviscerate and Envenom Bonus Damage (item set effect)
499 if(m_caster->GetDummyAura(37169))
500 damage += combo*40;
503 // Gouge
504 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
506 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.21f);
508 // Instant Poison
509 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
511 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
513 // Wound Poison
514 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
516 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
518 break;
520 case SPELLFAMILY_HUNTER:
522 // Mongoose Bite
523 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
525 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
527 // Counterattack
528 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
530 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
532 // Arcane Shot
533 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
535 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
537 // Steady Shot
538 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
540 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
541 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
543 // Explosive Trap Effect
544 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
546 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
548 break;
550 case SPELLFAMILY_PALADIN:
552 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
553 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
555 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
556 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
557 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
558 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
559 // Get stack of Holy Vengeance on the target added by caster
560 uint32 stacks = 0;
561 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
562 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
563 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
565 stacks = (*itr)->GetStackAmount();
566 break;
568 // + 10% for each application of Holy Vengeance on the target
569 if(stacks)
570 damage += damage * stacks * 10 /100;
572 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
573 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
575 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
576 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
577 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
578 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
580 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
581 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
583 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
584 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
585 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
586 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
588 // Hammer of the Righteous
589 else if(m_spellInfo->SpellFamilyFlags&0x0004000000000000LL)
591 // Add main hand dps * effect[2] amount
592 float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
593 int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
594 damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
596 // Shield of Righteousness
597 else if(m_spellInfo->SpellFamilyFlags&0x0010000000000000LL)
599 damage+=int32(m_caster->GetShieldBlockValue());
601 break;
605 if(damage >= 0)
606 m_damage+= damage;
610 void Spell::EffectDummy(uint32 i)
612 if(!unitTarget && !gameObjTarget && !itemTarget)
613 return;
615 // selection by spell family
616 switch(m_spellInfo->SpellFamilyName)
618 case SPELLFAMILY_GENERIC:
620 switch(m_spellInfo->Id )
622 case 8063: // Deviate Fish
624 if(m_caster->GetTypeId() != TYPEID_PLAYER)
625 return;
627 uint32 spell_id = 0;
628 switch(urand(1,5))
630 case 1: spell_id = 8064; break; // Sleepy
631 case 2: spell_id = 8065; break; // Invigorate
632 case 3: spell_id = 8066; break; // Shrink
633 case 4: spell_id = 8067; break; // Party Time!
634 case 5: spell_id = 8068; break; // Healthy Spirit
636 m_caster->CastSpell(m_caster,spell_id,true,NULL);
637 return;
639 case 8213: // Savory Deviate Delight
641 if(m_caster->GetTypeId() != TYPEID_PLAYER)
642 return;
644 uint32 spell_id = 0;
645 switch(urand(1,2))
647 // Flip Out - ninja
648 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
649 // Yaaarrrr - pirate
650 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
652 m_caster->CastSpell(m_caster,spell_id,true,NULL);
653 return;
655 case 8593: // Symbol of life (restore creature to life)
656 case 31225: // Shimmering Vessel (restore creature to life)
658 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
659 return;
660 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
661 return;
663 case 12162: // Deep wounds
664 case 12850: // (now good common check for this spells)
665 case 12868:
667 if(!unitTarget)
668 return;
670 float damage;
671 // DW should benefit of attack power, damage percent mods etc.
672 // TODO: check if using offhand damage is correct and if it should be divided by 2
673 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
674 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
675 else
676 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
678 switch (m_spellInfo->Id)
680 case 12850: damage *= 0.2f; break;
681 case 12162: damage *= 0.4f; break;
682 case 12868: damage *= 0.6f; break;
683 default:
684 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
685 return;
688 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
689 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
690 return;
692 case 13120: // net-o-matic
694 if(!unitTarget)
695 return;
697 uint32 spell_id = 0;
699 uint32 roll = urand(0, 99);
701 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
702 spell_id = 16566;
703 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
704 spell_id = 13119;
705 else // normal root
706 spell_id = 13099;
708 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
709 return;
711 case 13567: // Dummy Trigger
713 // can be used for different aura triggering, so select by aura
714 if(!m_triggeredByAuraSpell || !unitTarget)
715 return;
717 switch(m_triggeredByAuraSpell->Id)
719 case 26467: // Persistent Shield
720 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
721 break;
722 default:
723 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
724 break;
726 return;
728 case 15998: // Capture Worg Pup
729 case 29435: // Capture Female Kaliri Hatchling
731 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
732 return;
734 Creature* creatureTarget = (Creature*)unitTarget;
735 creatureTarget->setDeathState(JUST_DIED);
736 creatureTarget->RemoveCorpse();
737 creatureTarget->SetHealth(0); // just for nice GM-mode view
738 return;
740 case 16589: // Noggenfogger Elixir
742 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
743 return;
745 uint32 spell_id = 0;
746 switch(urand(1,3))
748 case 1: spell_id = 16595; break;
749 case 2: spell_id = 16593; break;
750 default:spell_id = 16591; break;
753 m_caster->CastSpell(m_caster,spell_id,true,NULL);
754 return;
756 case 17251: // Spirit Healer Res
758 if(!unitTarget || !m_originalCaster)
759 return;
761 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
763 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
764 data << unitTarget->GetGUID();
765 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
767 return;
769 case 17271: // Test Fetid Skull
771 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
772 return;
774 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
776 m_caster->CastSpell(m_caster,spell_id,true,NULL);
777 return;
779 case 20577: // Cannibalize
780 if (unitTarget)
781 m_caster->CastSpell(m_caster,20578,false,NULL);
782 return;
783 case 23019: // Crystal Prison Dummy DND
785 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
786 return;
788 Creature* creatureTarget = (Creature*)unitTarget;
789 if(creatureTarget->isPet())
790 return;
792 GameObject* pGameObj = new GameObject;
794 Map *map = creatureTarget->GetMap();
796 // create before death for get proper coordinates
797 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
798 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
799 creatureTarget->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY) )
801 delete pGameObj;
802 return;
805 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
806 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
807 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
808 pGameObj->SetSpellId(m_spellInfo->Id);
810 creatureTarget->setDeathState(JUST_DIED);
811 creatureTarget->RemoveCorpse();
812 creatureTarget->SetHealth(0); // just for nice GM-mode view
814 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy");
815 map->Add(pGameObj);
817 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
818 data << uint64(pGameObj->GetGUID());
819 m_caster->SendMessageToSet(&data,true);
821 return;
823 case 23074: // Arcanite Dragonling
824 if (!m_CastItem) return;
825 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
826 return;
827 case 23075: // Mithril Mechanical Dragonling
828 if (!m_CastItem) return;
829 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
830 return;
831 case 23076: // Mechanical Dragonling
832 if (!m_CastItem) return;
833 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
834 return;
835 case 23133: // Gnomish Battle Chicken
836 if (!m_CastItem) return;
837 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
838 return;
839 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
841 int32 r = irand(0, 119);
842 if ( r < 20 ) // 1/6 polymorph
843 m_caster->CastSpell(m_caster,23444,true);
844 else if ( r < 100 ) // 4/6 evil twin
845 m_caster->CastSpell(m_caster,23445,true);
846 else // 1/6 miss the target
847 m_caster->CastSpell(m_caster,36902,true);
848 return;
850 case 23453: // Ultrasafe Transporter: Gadgetzan
851 if ( roll_chance_i(50) ) // success
852 m_caster->CastSpell(m_caster,23441,true);
853 else // failure
854 m_caster->CastSpell(m_caster,23446,true);
855 return;
856 case 23645: // Hourglass Sand
857 m_caster->RemoveAurasDueToSpell(23170);
858 return;
859 case 23725: // Gift of Life (warrior bwl trinket)
860 m_caster->CastSpell(m_caster,23782,true);
861 m_caster->CastSpell(m_caster,23783,true);
862 return;
863 case 25860: // Reindeer Transformation
865 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
866 return;
868 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
869 float speed = m_caster->GetSpeedRate(MOVE_RUN);
871 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
873 //5 different spells used depending on mounted speed and if mount can fly or not
874 if (flyspeed >= 4.1f)
875 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
876 else if (flyspeed >= 3.8f)
877 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
878 else if (flyspeed >= 1.6f)
879 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
880 else if (speed >= 2.0f)
881 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
882 else
883 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
885 return;
887 //case 26074: // Holiday Cheer
888 // return; -- implemented at client side
889 case 28006: // Arcane Cloaking
891 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER )
892 m_caster->CastSpell(unitTarget,29294,true);
893 return;
895 case 28730: // Arcane Torrent (Mana)
897 Aura * dummy = m_caster->GetDummyAura(28734);
898 if (dummy)
900 int32 bp = damage * dummy->GetStackAmount();
901 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
902 m_caster->RemoveAurasDueToSpell(28734);
904 return;
906 case 29200: // Purify Helboar Meat
908 if( m_caster->GetTypeId() != TYPEID_PLAYER )
909 return;
911 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
913 m_caster->CastSpell(m_caster,spell_id,true,NULL);
914 return;
916 case 29858: // Soulshatter
917 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
918 m_caster->CastSpell(unitTarget,32835,true);
919 return;
920 case 30458: // Nigh Invulnerability
921 if (!m_CastItem) return;
922 if(roll_chance_i(86)) // success
923 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
924 else // backfire in 14% casts
925 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
926 return;
927 case 30507: // Poultryizer
928 if (!m_CastItem) return;
929 if(roll_chance_i(80)) // success
930 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
931 else // backfire 20%
932 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
933 return;
934 case 33060: // Make a Wish
936 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
937 return;
939 uint32 spell_id = 0;
941 switch(urand(1,5))
943 case 1: spell_id = 33053; break;
944 case 2: spell_id = 33057; break;
945 case 3: spell_id = 33059; break;
946 case 4: spell_id = 33062; break;
947 case 5: spell_id = 33064; break;
950 m_caster->CastSpell(m_caster,spell_id,true,NULL);
951 return;
953 case 35745:
955 uint32 spell_id;
956 switch(m_caster->GetAreaId())
958 case 3900: spell_id = 35743; break;
959 case 3742: spell_id = 35744; break;
960 default: return;
963 m_caster->CastSpell(m_caster,spell_id,true);
964 return;
966 case 37674: // Chaos Blast
968 if(!unitTarget)
969 return;
971 int32 basepoints0 = 100;
972 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
973 return;
975 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
977 // selecting one from Bloodstained Fortune item
978 uint32 newitemid;
979 switch(urand(1,20))
981 case 1: newitemid = 32688; break;
982 case 2: newitemid = 32689; break;
983 case 3: newitemid = 32690; break;
984 case 4: newitemid = 32691; break;
985 case 5: newitemid = 32692; break;
986 case 6: newitemid = 32693; break;
987 case 7: newitemid = 32700; break;
988 case 8: newitemid = 32701; break;
989 case 9: newitemid = 32702; break;
990 case 10: newitemid = 32703; break;
991 case 11: newitemid = 32704; break;
992 case 12: newitemid = 32705; break;
993 case 13: newitemid = 32706; break;
994 case 14: newitemid = 32707; break;
995 case 15: newitemid = 32708; break;
996 case 16: newitemid = 32709; break;
997 case 17: newitemid = 32710; break;
998 case 18: newitemid = 32711; break;
999 case 19: newitemid = 32712; break;
1000 case 20: newitemid = 32713; break;
1001 default:
1002 return;
1005 DoCreateItem(i,newitemid);
1006 return;
1008 // Demon Broiled Surprise
1009 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1010 case 43723:
1012 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1013 return;
1015 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1016 return;
1019 case 44875: // Complete Raptor Capture
1021 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1022 return;
1024 Creature* creatureTarget = (Creature*)unitTarget;
1026 creatureTarget->setDeathState(JUST_DIED);
1027 creatureTarget->RemoveCorpse();
1028 creatureTarget->SetHealth(0); // just for nice GM-mode view
1030 //cast spell Raptor Capture Credit
1031 m_caster->CastSpell(m_caster,42337,true,NULL);
1032 return;
1034 case 34665: //Administer Antidote
1036 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1037 return;
1039 if(!unitTarget)
1040 return;
1042 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1043 if(!tempSummon)
1044 return;
1046 uint32 health = tempSummon->GetHealth();
1048 float x = tempSummon->GetPositionX();
1049 float y = tempSummon->GetPositionY();
1050 float z = tempSummon->GetPositionZ();
1051 float o = tempSummon->GetOrientation();
1052 tempSummon->UnSummon();
1054 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1055 if (!pCreature)
1056 return;
1058 pCreature->SetHealth(health);
1059 ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992,pCreature);
1061 if (pCreature->AI())
1062 pCreature->AI()->AttackStart(m_caster);
1064 return;
1066 case 44997: // Converting Sentry
1068 //Converted Sentry Credit
1069 m_caster->CastSpell(m_caster, 45009, true);
1070 return;
1072 case 45030: // Impale Emissary
1074 // Emissary of Hate Credit
1075 m_caster->CastSpell(m_caster, 45088, true);
1076 return;
1078 case 50243: // Teach Language
1080 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1081 return;
1083 // spell has a 1/3 chance to trigger one of the below
1084 if(roll_chance_i(66))
1085 return;
1086 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1088 // 1000001 - gnomish binary
1089 m_caster->CastSpell(m_caster, 50242, true);
1091 else
1093 // 01001000 - goblin binary
1094 m_caster->CastSpell(m_caster, 50246, true);
1097 return;
1099 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1101 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1102 return;
1104 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1105 bg->EventPlayerDroppedFlag((Player*)m_caster);
1107 m_caster->CastSpell(m_caster, 30452, true, NULL);
1108 return;
1110 case 51592: // Pickup Primordial Hatchling
1112 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1113 return;
1115 Creature* creatureTarget = (Creature*)unitTarget;
1117 creatureTarget->setDeathState(JUST_DIED);
1118 creatureTarget->RemoveCorpse();
1119 creatureTarget->SetHealth(0); // just for nice GM-mode view
1120 return;
1123 case 52308:
1125 switch(i)
1127 case 0:
1129 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
1130 uint32 reqAuraID = m_spellInfo->CalculateSimpleValue(1);
1132 if (m_caster->HasAura(reqAuraID,0))
1133 m_caster->CastSpell(m_caster,spellID,true,NULL);
1134 return;
1136 case 1:
1137 return; // additional data for dummy[0]
1139 return;
1141 case 53341:
1142 case 53343:
1144 m_caster->CastSpell(m_caster,54586,true);
1145 return;
1147 case 58418: // Portal to Orgrimmar
1148 case 58420: // Portal to Stormwind
1149 return; // implemented in EffectScript[0]
1152 //All IconID Check in there
1153 switch(m_spellInfo->SpellIconID)
1155 // Berserking (troll racial traits)
1156 case 1661:
1158 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1159 int32 melee_mod = 10;
1160 if (healthPerc <= 40)
1161 melee_mod = 30;
1162 if (healthPerc < 100 && healthPerc > 40)
1163 melee_mod = 10+(100-healthPerc)/3;
1165 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1166 int32 hasteModBasePoints1 = (5-melee_mod);
1167 int32 hasteModBasePoints2 = 5;
1169 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1170 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1171 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1172 return;
1175 break;
1177 case SPELLFAMILY_MAGE:
1178 switch(m_spellInfo->Id )
1180 case 11958: // Cold Snap
1182 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1183 return;
1185 // immediately finishes the cooldown on Frost spells
1186 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1187 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1189 if (itr->second->state == PLAYERSPELL_REMOVED)
1190 continue;
1192 uint32 classspell = itr->first;
1193 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1195 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1196 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1197 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1199 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1201 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1202 data << uint32(classspell);
1203 data << uint64(m_caster->GetGUID());
1204 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1207 return;
1209 case 32826:
1211 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1213 //Polymorph Cast Visual Rank 1
1214 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1215 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1217 return;
1220 break;
1221 case SPELLFAMILY_WARRIOR:
1222 // Charge
1223 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1225 int32 chargeBasePoints0 = damage;
1226 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1227 return;
1229 // Execute
1230 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1232 if(!unitTarget)
1233 return;
1235 uint32 rage = m_caster->GetPower(POWER_RAGE);
1236 // Glyph of Execution bonus
1237 if (Aura *aura = m_caster->GetDummyAura(58367))
1238 rage+=aura->GetModifier()->m_amount;
1240 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1241 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1242 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1243 m_caster->SetPower(POWER_RAGE,0);
1244 return;
1246 // Slam
1247 if(m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL)
1249 if(!unitTarget)
1250 return;
1251 m_damage+=m_caster->CalculateDamage(m_attackType, false);
1252 m_damage+=damage;
1253 return;
1255 // Concussion Blow
1256 if(m_spellInfo->SpellFamilyFlags & 0x0000000004000000LL)
1258 m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
1259 return;
1261 switch(m_spellInfo->Id)
1263 // Warrior's Wrath
1264 case 21977:
1266 if(!unitTarget)
1267 return;
1268 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1269 return;
1271 // Last Stand
1272 case 12975:
1274 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1275 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1276 return;
1278 // Bloodthirst
1279 case 23881:
1281 m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
1282 return;
1285 break;
1286 case SPELLFAMILY_WARLOCK:
1287 // Life Tap
1288 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1290 // In 303 exist spirit depend
1291 uint32 spirit = uint32(m_caster->GetStat(STAT_SPIRIT));
1292 switch (m_spellInfo->Id)
1294 case 1454: damage+=spirit; break;
1295 case 1455: damage+=spirit*15/10; break;
1296 case 1456: damage+=spirit*2; break;
1297 case 11687: damage+=spirit*25/10; break;
1298 case 11688:
1299 case 11689:
1300 case 27222:
1301 case 57946: damage+=spirit*3; break;
1302 default:
1303 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1304 return;
1306 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1307 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1308 if(unitTarget && (int32(unitTarget->GetHealth()) > damage))
1310 // Shouldn't Appear in Combat Log
1311 unitTarget->ModifyHealth(-damage);
1313 int32 mana = damage;
1314 // Improved Life Tap mod
1315 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1316 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1318 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1319 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1321 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1323 // Mana Feed
1324 int32 manaFeedVal = 0;
1325 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1326 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1328 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1329 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1331 if(manaFeedVal > 0)
1333 manaFeedVal = manaFeedVal * mana / 100;
1334 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1337 else
1338 SendCastResult(SPELL_FAILED_FIZZLE);
1339 return;
1341 break;
1342 case SPELLFAMILY_PRIEST:
1343 // Penance
1344 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1346 if (!unitTarget)
1347 return;
1349 int hurt = 0;
1350 int heal = 0;
1351 switch(m_spellInfo->Id)
1353 case 47540: hurt = 47758; heal = 47757; break;
1354 case 53005: hurt = 53001; heal = 52986; break;
1355 case 53006: hurt = 53002; heal = 52987; break;
1356 case 53007: hurt = 53003; heal = 52988; break;
1357 default:
1358 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1359 return;
1361 if (m_caster->IsFriendlyTo(unitTarget))
1362 m_caster->CastSpell(unitTarget, heal, true, 0);
1363 else
1364 m_caster->CastSpell(unitTarget, hurt, true, 0);
1365 return;
1367 break;
1368 case SPELLFAMILY_DRUID:
1369 // Starfall
1370 if (m_spellInfo->SpellFamilyFlags2 & 0x00000100LL)
1372 //Shapeshifting into an animal form or mounting cancels the effect.
1373 if(m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
1375 if(m_triggeredByAuraSpell)
1376 m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
1377 return;
1380 //Any effect which causes you to lose control of your character will supress the starfall effect.
1381 if(m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED))
1382 return;
1384 switch(m_spellInfo->Id)
1386 case 50286: m_caster->CastSpell(unitTarget, 50288, true); return;
1387 case 53196: m_caster->CastSpell(unitTarget, 53191, true); return;
1388 case 53197: m_caster->CastSpell(unitTarget, 53194, true); return;
1389 case 53198: m_caster->CastSpell(unitTarget, 53195, true); return;
1390 default:
1391 sLog.outError("Spell::EffectDummy: Unhandeled Starfall spell rank %u",m_spellInfo->Id);
1392 return;
1395 break;
1396 case SPELLFAMILY_ROGUE:
1397 switch(m_spellInfo->Id )
1399 case 5938: // Shiv
1401 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1402 return;
1404 Player *pCaster = ((Player*)m_caster);
1406 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1407 if(!item)
1408 return;
1410 // all poison enchantments is temporary
1411 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1412 if(!enchant_id)
1413 return;
1415 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1416 if(!pEnchant)
1417 return;
1419 for (int s=0;s<3;s++)
1421 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1422 continue;
1424 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1425 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1426 continue;
1428 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1431 m_caster->CastSpell(unitTarget, 5940, true);
1432 return;
1434 case 14185: // Preparation Rogue
1436 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1437 return;
1439 //immediately finishes the cooldown on certain Rogue abilities
1440 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1441 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1443 uint32 classspell = itr->first;
1444 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1446 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1448 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1450 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1451 data << uint32(classspell);
1452 data << uint64(m_caster->GetGUID());
1453 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1456 return;
1458 case 31231: // Cheat Death
1460 m_caster->CastSpell(m_caster,45182,true);
1461 return;
1464 break;
1465 case SPELLFAMILY_HUNTER:
1466 // Steady Shot
1467 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1469 if( !unitTarget || !unitTarget->isAlive())
1470 return;
1472 bool found = false;
1474 // check dazed affect
1475 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1476 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1478 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1480 found = true;
1481 break;
1485 if(found)
1486 m_damage+= damage;
1487 return;
1490 switch(m_spellInfo->Id)
1492 case 23989: //Readiness talent
1494 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1495 return;
1497 //immediately finishes the cooldown for hunter abilities
1498 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1499 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1501 uint32 classspell = itr->first;
1502 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1504 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1506 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1508 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1509 data << uint32(classspell);
1510 data << uint64(m_caster->GetGUID());
1511 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1514 return;
1516 case 37506: // Scatter Shot
1518 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1519 return;
1521 // break Auto Shot and autohit
1522 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1523 m_caster->AttackStop();
1524 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1525 return;
1528 break;
1529 case SPELLFAMILY_PALADIN:
1530 switch(m_spellInfo->SpellIconID)
1532 case 156: // Holy Shock
1534 if(!unitTarget)
1535 return;
1537 int hurt = 0;
1538 int heal = 0;
1540 switch(m_spellInfo->Id)
1542 case 20473: hurt = 25912; heal = 25914; break;
1543 case 20929: hurt = 25911; heal = 25913; break;
1544 case 20930: hurt = 25902; heal = 25903; break;
1545 case 27174: hurt = 27176; heal = 27175; break;
1546 case 33072: hurt = 33073; heal = 33074; break;
1547 case 48824: hurt = 48822; heal = 48820; break;
1548 case 48825: hurt = 48823; heal = 48821; break;
1549 default:
1550 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1551 return;
1554 if(m_caster->IsFriendlyTo(unitTarget))
1555 m_caster->CastSpell(unitTarget, heal, true, 0);
1556 else
1557 m_caster->CastSpell(unitTarget, hurt, true, 0);
1559 return;
1561 case 561: // Judgement of command
1563 if(!unitTarget)
1564 return;
1566 uint32 spell_id = m_currentBasePoints[i]+1;
1567 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1568 if(!spell_proto)
1569 return;
1571 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1573 // decreased damage (/2) for non-stunned target.
1574 SpellModifier *mod = new SpellModifier;
1575 mod->op = SPELLMOD_DAMAGE;
1576 mod->value = -50;
1577 mod->type = SPELLMOD_PCT;
1578 mod->spellId = m_spellInfo->Id;
1579 mod->mask = 0x0000020000000000LL;
1580 mod->mask2= 0LL;
1582 ((Player*)m_caster)->AddSpellMod(mod, true);
1583 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1584 // mod deleted
1585 ((Player*)m_caster)->AddSpellMod(mod, false);
1587 else
1588 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1590 return;
1594 switch(m_spellInfo->Id)
1596 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1597 case 20187:
1599 if (!unitTarget)
1600 return;
1601 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1602 return;
1604 case 31789: // Righteous Defense (step 1)
1606 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1608 // non-standard cast requirement check
1609 if (!unitTarget || unitTarget->getAttackers().empty())
1611 // clear cooldown at fail
1612 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1614 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1616 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1617 data << uint32(m_spellInfo->Id);
1618 data << uint64(m_caster->GetGUID());
1619 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1622 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1623 return;
1626 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1627 // Clear targets for eff 1
1628 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1629 ihit->effectMask &= ~(1<<1);
1631 // not empty (checked)
1632 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1634 // chance to be selected from list
1635 float chance = 100.0f/attackers.size();
1636 uint32 count=0;
1637 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1639 if(!roll_chance_f(chance))
1640 continue;
1641 ++count;
1642 AddUnitTarget((*aItr), 1);
1645 // now let next effect cast spell at each target.
1646 return;
1648 case 37877: // Blessing of Faith
1650 if(!unitTarget)
1651 return;
1653 uint32 spell_id = 0;
1654 switch(unitTarget->getClass())
1656 case CLASS_DRUID: spell_id = 37878; break;
1657 case CLASS_PALADIN: spell_id = 37879; break;
1658 case CLASS_PRIEST: spell_id = 37880; break;
1659 case CLASS_SHAMAN: spell_id = 37881; break;
1660 default: return; // ignore for not healing classes
1663 m_caster->CastSpell(m_caster,spell_id,true);
1664 return;
1667 break;
1668 case SPELLFAMILY_SHAMAN:
1669 //Shaman Rockbiter Weapon
1670 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1672 // TODO: use expect spell for enchant (if exist talent)
1673 // In 3.0.3 no mods present for rockbiter
1674 uint32 spell_id = 0;
1675 switch(m_spellInfo->Id)
1677 case 8017: spell_id = 36494; break; // Rank 1
1678 case 8018: spell_id = 36750; break; // Rank 2
1679 case 8019: spell_id = 36755; break; // Rank 3
1680 case 10399: spell_id = 36759; break; // Rank 4
1681 default:
1682 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1683 return;
1686 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1688 if(!spellInfo)
1690 sLog.outError("WORLD: unknown spell id %i", spell_id);
1691 return;
1694 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1695 return;
1697 for(int j = BASE_ATTACK; j <= OFF_ATTACK; ++j)
1699 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(j)))
1701 if(item->IsFitToSpellRequirements(m_spellInfo))
1703 Spell *spell = new Spell(m_caster, spellInfo, true);
1705 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1706 // at calculation applied affect from Elemental Weapons talent
1707 // real enchantment damage-1
1708 spell->m_currentBasePoints[1] = damage-1;
1710 SpellCastTargets targets;
1711 targets.setItemTarget( item );
1712 spell->prepare(&targets);
1716 return;
1718 // Healing Stream Totem
1719 if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
1721 m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1722 return;
1724 // Mana Spring Totem
1725 if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
1727 if(unitTarget->getPowerType()!=POWER_MANA)
1728 return;
1729 m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1730 return;
1732 if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
1734 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1735 return;
1736 // Glyph of Mana Tide
1737 Unit *owner = m_caster->GetOwner();
1738 if (owner)
1739 if (Aura *dummy = owner->GetDummyAura(55441))
1740 damage+=dummy->GetModifier()->m_amount;
1741 // Regenerate 6% of Total Mana Every 3 secs
1742 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1743 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1744 return;
1746 // Lava Lash
1747 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1749 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1750 return;
1751 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1752 if (item)
1754 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1755 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1756 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1758 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1759 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1760 (*itr)->GetCastItemGUID() == item->GetGUID())
1762 m_damage += m_damage * damage / 100;
1763 return;
1767 return;
1769 break;
1770 case SPELLFAMILY_DEATHKNIGHT:
1771 // Death Coil
1772 if(m_spellInfo->SpellFamilyFlags & 0x002000LL)
1774 if(m_caster->IsFriendlyTo(unitTarget))
1776 if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
1777 return;
1779 int32 bp = damage * 1.5f;
1780 m_caster->CastCustomSpell(unitTarget,47633,&bp,NULL,NULL,true);
1782 else
1784 int32 bp = damage;
1785 m_caster->CastCustomSpell(unitTarget,47632,&bp,NULL,NULL,true);
1787 return;
1789 break;
1792 // pet auras
1793 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1795 m_caster->AddPetAura(petSpell);
1796 return;
1799 // Script based implementation. Must be used only for not good for implementation in core spell effects
1800 // So called only for not proccessed cases
1801 if(gameObjTarget)
1802 Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget);
1803 else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT)
1804 Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget);
1805 else if(itemTarget)
1806 Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget);
1809 void Spell::EffectTriggerSpellWithValue(uint32 i)
1811 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1813 // normal case
1814 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1816 if(!spellInfo)
1818 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1819 return;
1822 int32 bp = damage;
1823 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1826 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1828 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1829 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1831 if(!spellInfo)
1833 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1834 return;
1837 finish();
1838 Spell *spell = new Spell(m_caster, spellInfo, true);
1840 SpellCastTargets targets;
1841 targets.setUnitTarget( unitTarget);
1842 spell->prepare(&targets);
1844 m_caster->SetCurrentCastedSpell(spell);
1845 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1849 void Spell::EffectForceCast(uint32 i)
1851 if( !unitTarget )
1852 return;
1854 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1856 // normal case
1857 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1859 if(!spellInfo)
1861 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1862 return;
1865 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1868 void Spell::EffectTriggerSpell(uint32 i)
1870 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1872 // special cases
1873 switch(triggered_spell_id)
1875 // Vanish
1876 case 18461:
1878 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1879 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1880 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1882 // if this spell is given to NPC it must handle rest by it's own AI
1883 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1884 return;
1886 // get highest rank of the Stealth spell
1887 uint32 spellId = 0;
1888 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1889 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1891 // only highest rank is shown in spell book, so simply check if shown in spell book
1892 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1893 continue;
1895 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1896 if (!spellInfo)
1897 continue;
1899 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1901 spellId = spellInfo->Id;
1902 break;
1906 // no Stealth spell found
1907 if (!spellId)
1908 return;
1910 // reset cooldown on it if needed
1911 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1912 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1914 m_caster->CastSpell(m_caster, spellId, true);
1915 return;
1917 // just skip
1918 case 23770: // Sayge's Dark Fortune of *
1919 // not exist, common cooldown can be implemented in scripts if need.
1920 return;
1921 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1922 case 29284:
1924 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1925 if (!spell)
1926 return;
1928 for (int j=0; j < spell->StackAmount; ++j)
1929 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1930 return;
1932 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1933 case 29286:
1935 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1936 if (!spell)
1937 return;
1939 for (int j=0; j < spell->StackAmount; ++j)
1940 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1941 return;
1943 // Righteous Defense
1944 case 31980:
1946 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1947 return;
1949 // Cloak of Shadows
1950 case 35729 :
1952 Unit::AuraMap& Auras = m_caster->GetAuras();
1953 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1955 // remove all harmful spells on you...
1956 if( // ignore positive and passive auras
1957 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1958 // ignore physical auras
1959 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1961 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1962 iter = Auras.begin();
1965 return;
1967 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1968 case 41967:
1970 if (Unit *pet = m_caster->GetPet())
1971 pet->CastSpell(pet, 28305, true);
1972 return;
1976 // normal case
1977 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1979 if(!spellInfo)
1981 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1982 return;
1985 // some triggered spells require specific equipment
1986 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1988 // main hand weapon required
1989 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1991 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1993 // skip spell if no weapon in slot or broken
1994 if(!item || item->IsBroken() )
1995 return;
1997 // skip spell if weapon not fit to triggered spell
1998 if(!item->IsFitToSpellRequirements(spellInfo))
1999 return;
2002 // offhand hand weapon required
2003 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
2005 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
2007 // skip spell if no weapon in slot or broken
2008 if(!item || item->IsBroken() )
2009 return;
2011 // skip spell if weapon not fit to triggered spell
2012 if(!item->IsFitToSpellRequirements(spellInfo))
2013 return;
2017 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
2018 bool instant = false;
2019 for(uint32 j = i+1; j < 3; ++j)
2021 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
2023 instant = true;
2024 break;
2028 if(instant)
2030 if (unitTarget)
2031 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
2033 else
2034 m_TriggerSpells.push_back(spellInfo);
2037 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
2039 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
2041 // normal case
2042 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
2044 if(!spellInfo)
2046 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
2047 m_spellInfo->Id,effect_idx,triggered_spell_id);
2048 return;
2051 if (m_CastItem)
2052 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
2054 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
2057 void Spell::EffectJump(uint32 i)
2059 if(m_caster->isInFlight())
2060 return;
2062 // Init dest coordinates
2063 float x,y,z,o;
2064 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
2066 x = m_targets.m_destX;
2067 y = m_targets.m_destY;
2068 z = m_targets.m_destZ;
2070 if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM)
2072 // explicit cast data from client or server-side cast
2073 // some spell at client send caster
2074 Unit* pTarget = NULL;
2075 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster)
2076 pTarget = m_targets.getUnitTarget();
2077 else if(unitTarget->getVictim())
2078 pTarget = m_caster->getVictim();
2079 else if(m_caster->GetTypeId() == TYPEID_PLAYER)
2080 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2082 o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
2084 else
2085 o = m_caster->GetOrientation();
2087 else if(unitTarget)
2089 unitTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2090 o = m_caster->GetOrientation();
2092 else if(gameObjTarget)
2094 gameObjTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2095 o = m_caster->GetOrientation();
2097 else
2099 sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id );
2100 return;
2103 m_caster->NearTeleportTo(x,y,z,o,true);
2106 void Spell::EffectTeleportUnits(uint32 i)
2108 if(!unitTarget || unitTarget->isInFlight())
2109 return;
2111 switch (m_spellInfo->EffectImplicitTargetB[i])
2113 case TARGET_INNKEEPER_COORDINATES:
2115 // Only players can teleport to innkeeper
2116 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2117 return;
2119 ((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);
2120 return;
2122 case TARGET_AREAEFFECT_INSTANT: // in all cases first TARGET_TABLE_X_Y_Z_COORDINATES
2123 case TARGET_TABLE_X_Y_Z_COORDINATES:
2125 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2126 if(!st)
2128 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id );
2129 return;
2132 if(st->target_mapId==unitTarget->GetMapId())
2133 unitTarget->NearTeleportTo(st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster);
2134 else if(unitTarget->GetTypeId()==TYPEID_PLAYER)
2135 ((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);
2136 break;
2138 case TARGET_BEHIND_VICTIM:
2140 Unit *pTarget = NULL;
2142 // explicit cast data from client or server-side cast
2143 // some spell at client send caster
2144 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=unitTarget)
2145 pTarget = m_targets.getUnitTarget();
2146 else if(unitTarget->getVictim())
2147 pTarget = unitTarget->getVictim();
2148 else if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2149 pTarget = ObjectAccessor::GetUnit(*unitTarget, ((Player*)unitTarget)->GetSelection());
2151 // Init dest coordinates
2152 float x = m_targets.m_destX;
2153 float y = m_targets.m_destY;
2154 float z = m_targets.m_destZ;
2155 float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation();
2156 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2157 return;
2159 default:
2161 // If not exist data for dest location - return
2162 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2164 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2165 return;
2167 // Init dest coordinates
2168 float x = m_targets.m_destX;
2169 float y = m_targets.m_destY;
2170 float z = m_targets.m_destZ;
2171 float orientation = unitTarget->GetOrientation();
2172 // Teleport
2173 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2174 return;
2178 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2179 switch ( m_spellInfo->Id )
2181 // Dimensional Ripper - Everlook
2182 case 23442:
2184 int32 r = irand(0, 119);
2185 if ( r >= 70 ) // 7/12 success
2187 if ( r < 100 ) // 4/12 evil twin
2188 m_caster->CastSpell(m_caster,23445,true);
2189 else // 1/12 fire
2190 m_caster->CastSpell(m_caster,23449,true);
2192 return;
2194 // Ultrasafe Transporter: Toshley's Station
2195 case 36941:
2197 if ( roll_chance_i(50) ) // 50% success
2199 int32 rand_eff = urand(1,7);
2200 switch ( rand_eff )
2202 case 1:
2203 // soul split - evil
2204 m_caster->CastSpell(m_caster,36900,true);
2205 break;
2206 case 2:
2207 // soul split - good
2208 m_caster->CastSpell(m_caster,36901,true);
2209 break;
2210 case 3:
2211 // Increase the size
2212 m_caster->CastSpell(m_caster,36895,true);
2213 break;
2214 case 4:
2215 // Decrease the size
2216 m_caster->CastSpell(m_caster,36893,true);
2217 break;
2218 case 5:
2219 // Transform
2221 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2222 m_caster->CastSpell(m_caster,36897,true);
2223 else
2224 m_caster->CastSpell(m_caster,36899,true);
2225 break;
2227 case 6:
2228 // chicken
2229 m_caster->CastSpell(m_caster,36940,true);
2230 break;
2231 case 7:
2232 // evil twin
2233 m_caster->CastSpell(m_caster,23445,true);
2234 break;
2237 return;
2239 // Dimensional Ripper - Area 52
2240 case 36890:
2242 if ( roll_chance_i(50) ) // 50% success
2244 int32 rand_eff = urand(1,4);
2245 switch ( rand_eff )
2247 case 1:
2248 // soul split - evil
2249 m_caster->CastSpell(m_caster,36900,true);
2250 break;
2251 case 2:
2252 // soul split - good
2253 m_caster->CastSpell(m_caster,36901,true);
2254 break;
2255 case 3:
2256 // Increase the size
2257 m_caster->CastSpell(m_caster,36895,true);
2258 break;
2259 case 4:
2260 // Transform
2262 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2263 m_caster->CastSpell(m_caster,36897,true);
2264 else
2265 m_caster->CastSpell(m_caster,36899,true);
2266 break;
2270 return;
2275 void Spell::EffectApplyAura(uint32 i)
2277 if(!unitTarget)
2278 return;
2280 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2281 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2282 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2283 return;
2285 Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
2286 if(!caster)
2287 return;
2289 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2291 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2293 // Now Reduce spell duration using data received at spell hit
2294 int32 duration = Aur->GetAuraMaxDuration();
2295 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2296 Aur->setDiminishGroup(m_diminishGroup);
2298 // if Aura removed and deleted, do not continue.
2299 if(duration== 0 && !(Aur->IsPermanent()))
2301 delete Aur;
2302 return;
2305 if(duration != Aur->GetAuraMaxDuration())
2307 Aur->SetAuraMaxDuration(duration);
2308 Aur->SetAuraDuration(duration);
2311 bool added = unitTarget->AddAura(Aur);
2313 // Aura not added and deleted in AddAura call;
2314 if (!added)
2315 return;
2317 // found crash at character loading, broken pointer to Aur...
2318 // Aur was deleted in AddAura()...
2319 if(!Aur)
2320 return;
2322 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2323 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2324 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2327 void Spell::EffectUnlearnSpecialization( uint32 i )
2329 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2330 return;
2332 Player *_player = (Player*)unitTarget;
2333 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2335 _player->removeSpell(spellToUnlearn);
2337 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2340 void Spell::EffectPowerDrain(uint32 i)
2342 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2343 return;
2345 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2347 if(!unitTarget)
2348 return;
2349 if(!unitTarget->isAlive())
2350 return;
2351 if(unitTarget->getPowerType() != drain_power)
2352 return;
2353 if(damage < 0)
2354 return;
2356 uint32 curPower = unitTarget->GetPower(drain_power);
2358 //add spell damage bonus
2359 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2361 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2362 uint32 power = damage;
2363 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2364 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2366 int32 new_damage;
2367 if(curPower < power)
2368 new_damage = curPower;
2369 else
2370 new_damage = power;
2372 unitTarget->ModifyPower(drain_power,-new_damage);
2374 // Don`t restore from self drain
2375 if(drain_power == POWER_MANA && m_caster != unitTarget)
2377 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2378 if(manaMultiplier==0)
2379 manaMultiplier = 1;
2381 if(Player *modOwner = m_caster->GetSpellModOwner())
2382 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2384 int32 gain = int32(new_damage*manaMultiplier);
2386 m_caster->ModifyPower(POWER_MANA,gain);
2387 //send log
2388 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2392 void Spell::EffectSendEvent(uint32 EffectIndex)
2395 we do not handle a flag dropping or clicking on flag in battleground by sendevent system
2397 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2398 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2401 void Spell::EffectPowerBurn(uint32 i)
2403 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2404 return;
2406 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2408 if(!unitTarget)
2409 return;
2410 if(!unitTarget->isAlive())
2411 return;
2412 if(unitTarget->getPowerType()!=powertype)
2413 return;
2414 if(damage < 0)
2415 return;
2417 // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
2418 if(m_spellInfo->ManaCostPercentage)
2420 uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
2421 damage = unitTarget->GetMaxPower(powertype) * damage / 100;
2422 if(damage > maxdamage) damage = maxdamage;
2425 int32 curPower = int32(unitTarget->GetPower(powertype));
2427 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2428 uint32 power = damage;
2429 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2430 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2432 int32 new_damage = (curPower < power) ? curPower : power;
2434 unitTarget->ModifyPower(powertype,-new_damage);
2435 float multiplier = m_spellInfo->EffectMultipleValue[i];
2437 if(Player *modOwner = m_caster->GetSpellModOwner())
2438 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2440 new_damage = int32(new_damage*multiplier);
2441 m_damage+=new_damage;
2444 void Spell::EffectHeal( uint32 /*i*/ )
2446 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2448 // Try to get original caster
2449 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2451 // Skip if m_originalCaster not available
2452 if (!caster)
2453 return;
2455 int32 addhealth = damage;
2457 // Vessel of the Naaru (Vial of the Sunwell trinket)
2458 if (m_spellInfo->Id == 45064)
2460 // Amount of heal - depends from stacked Holy Energy
2461 int damageAmount = 0;
2462 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2463 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2464 if((*i)->GetId() == 45062)
2465 damageAmount+=(*i)->GetModifier()->m_amount;
2466 if (damageAmount)
2467 m_caster->RemoveAurasDueToSpell(45062);
2469 addhealth += damageAmount;
2471 // Swiftmend - consumes Regrowth or Rejuvenation
2472 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2474 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2475 // find most short by duration
2476 Aura *targetAura = NULL;
2477 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2479 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2480 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2482 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2483 targetAura = *i;
2487 if(!targetAura)
2489 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2490 return;
2492 int idx = 0;
2493 while(idx < 3)
2495 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2496 break;
2497 idx++;
2500 int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
2501 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2502 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2504 addhealth += tickheal * tickcount;
2506 else
2507 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
2509 m_healing+=addhealth;
2513 void Spell::EffectHealPct( uint32 /*i*/ )
2515 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2517 // Try to get original caster
2518 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2520 // Skip if m_originalCaster not available
2521 if (!caster)
2522 return;
2524 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2525 if(Player* modOwner = m_caster->GetSpellModOwner())
2526 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this);
2528 int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo);
2529 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2533 void Spell::EffectHealMechanical( uint32 /*i*/ )
2535 // Mechanic creature type should be correctly checked by targetCreatureType field
2536 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2538 // Try to get original caster
2539 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2541 // Skip if m_originalCaster not available
2542 if (!caster)
2543 return;
2545 uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
2546 caster->DealHeal(unitTarget, addhealth, m_spellInfo);
2550 void Spell::EffectHealthLeech(uint32 i)
2552 if(!unitTarget)
2553 return;
2554 if(!unitTarget->isAlive())
2555 return;
2557 if(damage < 0)
2558 return;
2560 sLog.outDebug("HealthLeech :%i", damage);
2562 float multiplier = m_spellInfo->EffectMultipleValue[i];
2564 if(Player *modOwner = m_caster->GetSpellModOwner())
2565 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2567 int32 new_damage = int32(damage*multiplier);
2568 uint32 curHealth = unitTarget->GetHealth();
2569 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage );
2570 if(curHealth < new_damage)
2571 new_damage = curHealth;
2573 if(m_caster->isAlive())
2575 new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
2576 m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo);
2578 // m_healthLeech+=tmpvalue;
2579 // m_damage+=new_damage;
2582 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2584 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2585 return;
2587 Player* player = (Player*)unitTarget;
2589 uint32 newitemid = itemtype;
2590 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2591 if(!pProto)
2593 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2594 return;
2597 uint32 num_to_add;
2599 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2600 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2602 int32 basePoints = m_currentBasePoints[i];
2603 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2604 if (randomPoints)
2605 num_to_add = basePoints + irand(1, randomPoints);
2606 else
2607 num_to_add = basePoints + 1;
2609 else if (pProto->MaxCount == 1)
2610 num_to_add = 1;
2611 else if(player->getLevel() >= m_spellInfo->spellLevel)
2613 int32 basePoints = m_currentBasePoints[i];
2614 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2615 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2617 else
2618 num_to_add = 2;
2620 if (num_to_add < 1)
2621 num_to_add = 1;
2622 if (num_to_add > pProto->GetMaxStackSize())
2623 num_to_add = pProto->GetMaxStackSize();
2625 // init items_count to 1, since 1 item will be created regardless of specialization
2626 int items_count=1;
2627 // the chance to create additional items
2628 float additionalCreateChance=0.0f;
2629 // the maximum number of created additional items
2630 uint8 additionalMaxNum=0;
2631 // get the chance and maximum number for creating extra items
2632 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2634 // roll with this chance till we roll not to create or we create the max num
2635 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2636 ++items_count;
2639 // really will be created more items
2640 num_to_add *= items_count;
2642 // can the player store the new item?
2643 ItemPosCountVec dest;
2644 uint32 no_space = 0;
2645 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2646 if( msg != EQUIP_ERR_OK )
2648 // convert to possible store amount
2649 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2650 num_to_add -= no_space;
2651 else
2653 // if not created by another reason from full inventory or unique items amount limitation
2654 player->SendEquipError( msg, NULL, NULL );
2655 return;
2659 if(num_to_add)
2661 // create the new item and store it
2662 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2664 // was it successful? return error if not
2665 if(!pItem)
2667 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2668 return;
2671 // set the "Crafted by ..." property of the item
2672 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2673 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2675 // send info to the client
2676 if(pItem)
2677 player->SendNewItem(pItem, num_to_add, true, true);
2679 // we succeeded in creating at least one item, so a levelup is possible
2680 player->UpdateCraftSkill(m_spellInfo->Id);
2683 // for battleground marks send by mail if not add all expected
2684 if(no_space > 0 )
2686 BattleGroundTypeId bgType;
2687 switch(m_spellInfo->Id)
2689 case SPELL_AV_MARK_WINNER:
2690 case SPELL_AV_MARK_LOSER:
2691 bgType = BATTLEGROUND_AV;
2692 break;
2693 case SPELL_WS_MARK_WINNER:
2694 case SPELL_WS_MARK_LOSER:
2695 bgType = BATTLEGROUND_WS;
2696 break;
2697 case SPELL_AB_MARK_WINNER:
2698 case SPELL_AB_MARK_LOSER:
2699 bgType = BATTLEGROUND_AB;
2700 break;
2701 default:
2702 return;
2705 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2706 bg->SendRewardMarkByMail(player,newitemid,no_space);
2710 void Spell::EffectCreateItem(uint32 i)
2712 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2715 void Spell::EffectCreateItem2(uint32 i)
2717 // special case: generate using spell_loot_template
2718 if(!m_spellInfo->EffectItemType[i])
2720 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
2721 return;
2723 // create some random items
2724 ((Player*)m_caster)->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
2725 return;
2727 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2730 void Spell::EffectPersistentAA(uint32 i)
2732 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2734 if(Player* modOwner = m_caster->GetSpellModOwner())
2735 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2737 int32 duration = GetSpellDuration(m_spellInfo);
2738 DynamicObject* dynObj = new DynamicObject;
2739 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))
2741 delete dynObj;
2742 return;
2744 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2745 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2746 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2747 m_caster->AddDynObject(dynObj);
2748 dynObj->GetMap()->Add(dynObj);
2751 void Spell::EffectEnergize(uint32 i)
2753 if(!unitTarget)
2754 return;
2755 if(!unitTarget->isAlive())
2756 return;
2758 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2759 return;
2761 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2763 // Some level depends spells
2764 int multiplier = 0;
2765 int level_diff = 0;
2766 switch (m_spellInfo->Id)
2768 // Restore Energy
2769 case 9512:
2770 level_diff = m_caster->getLevel() - 40;
2771 multiplier = 2;
2772 break;
2773 // Blood Fury
2774 case 24571:
2775 level_diff = m_caster->getLevel() - 60;
2776 multiplier = 10;
2777 break;
2778 // Burst of Energy
2779 case 24532:
2780 level_diff = m_caster->getLevel() - 60;
2781 multiplier = 4;
2782 break;
2783 default:
2784 break;
2787 if (level_diff > 0)
2788 damage -= multiplier * level_diff;
2790 if(damage < 0)
2791 return;
2793 if(unitTarget->GetMaxPower(power) == 0)
2794 return;
2796 unitTarget->ModifyPower(power,damage);
2797 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2799 // Mad Alchemist's Potion
2800 if (m_spellInfo->Id == 45051)
2802 // find elixirs on target
2803 uint32 elixir_mask = 0;
2804 Unit::AuraMap& Auras = unitTarget->GetAuras();
2805 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2807 uint32 spell_id = itr->second->GetId();
2808 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2809 elixir_mask |= mask;
2812 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2813 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2815 // get all available elixirs by mask and spell level
2816 std::vector<uint32> elixirs;
2817 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2818 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2820 if (itr->second & elixir_mask)
2822 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2823 continue;
2825 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2826 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2827 continue;
2829 elixirs.push_back(itr->first);
2833 if (!elixirs.empty())
2835 // cast random elixir on target
2836 uint32 rand_spell = urand(0,elixirs.size()-1);
2837 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2842 void Spell::EffectEnergisePct(uint32 i)
2844 if(!unitTarget)
2845 return;
2846 if(!unitTarget->isAlive())
2847 return;
2849 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2850 return;
2852 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2854 uint32 maxPower = unitTarget->GetMaxPower(power);
2855 if(maxPower == 0)
2856 return;
2858 uint32 gain = damage * maxPower / 100;
2859 unitTarget->ModifyPower(power, gain);
2860 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2863 void Spell::SendLoot(uint64 guid, LootType loottype)
2865 Player* player = (Player*)m_caster;
2866 if (!player)
2867 return;
2869 if (gameObjTarget)
2871 if (Script->GOHello(player, gameObjTarget))
2872 return;
2874 switch (gameObjTarget->GetGoType())
2876 case GAMEOBJECT_TYPE_DOOR:
2877 case GAMEOBJECT_TYPE_BUTTON:
2878 gameObjTarget->UseDoorOrButton();
2879 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2880 return;
2882 case GAMEOBJECT_TYPE_QUESTGIVER:
2883 // start or end quest
2884 player->PrepareQuestMenu(guid);
2885 player->SendPreparedQuest(guid);
2886 return;
2888 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2889 // triggering linked GO
2890 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2891 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2892 return;
2894 case GAMEOBJECT_TYPE_GOOBER:
2895 // goober_scripts can be triggered if the player don't have the quest
2896 if (gameObjTarget->GetGOInfo()->goober.eventId)
2898 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2899 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2902 // cast goober spell
2903 if (gameObjTarget->GetGOInfo()->goober.questId)
2904 ///Quest require to be active for GO using
2905 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2906 return;
2908 gameObjTarget->AddUniqueUse(player);
2909 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2911 //TODO? Objective counting called without spell check but with quest objective check
2912 // if send spell id then this line will duplicate to spell casting call (double counting)
2913 // So we or have this line and not required in quest_template have reqSpellIdN
2914 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2915 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2917 // triggering linked GO
2918 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2919 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2921 return;
2923 case GAMEOBJECT_TYPE_CHEST:
2924 // TODO: possible must be moved to loot release (in different from linked triggering)
2925 if (gameObjTarget->GetGOInfo()->chest.eventId)
2927 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2928 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2931 // triggering linked GO
2932 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2933 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2935 // Don't return, let loots been taken
2936 default:
2937 break;
2941 // Send loot
2942 player->SendLoot(guid, loottype);
2945 void Spell::EffectOpenLock(uint32 effIndex)
2947 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2949 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2950 return;
2953 Player* player = (Player*)m_caster;
2955 uint32 lockId = 0;
2956 uint64 guid = 0;
2958 // Get lockId
2959 if(gameObjTarget)
2961 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2962 // Arathi Basin banner opening !
2963 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2964 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2966 //CanUseBattleGroundObject() already called in CheckCast()
2967 // in battleground check
2968 if(BattleGround *bg = player->GetBattleGround())
2970 // check if it's correct bg
2971 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2972 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2973 return;
2976 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2978 //CanUseBattleGroundObject() already called in CheckCast()
2979 // in battleground check
2980 if(BattleGround *bg = player->GetBattleGround())
2982 if(bg->GetTypeID() == BATTLEGROUND_EY)
2983 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2984 return;
2987 lockId = gameObjTarget->GetLockId();
2988 guid = gameObjTarget->GetGUID();
2990 else if(itemTarget)
2992 lockId = itemTarget->GetProto()->LockID;
2993 guid = itemTarget->GetGUID();
2995 else
2997 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2998 return;
3001 SkillType skillId = SKILL_NONE;
3002 int32 reqSkillValue = 0;
3003 int32 skillValue;
3005 SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue);
3006 if(res != SPELL_CAST_OK)
3008 SendCastResult(res);
3009 return;
3012 SendLoot(guid, LOOT_SKINNING);
3014 // not allow use skill grow at item base open
3015 if(!m_CastItem && skillId != SKILL_NONE)
3017 // update skill if really known
3018 if(uint32 pureSkillValue = player->GetPureSkillValue(skillId))
3020 if(gameObjTarget)
3022 // Allow one skill-up until respawned
3023 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3024 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) )
3025 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3027 else if(itemTarget)
3029 // Do one skill-up
3030 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
3036 void Spell::EffectSummonChangeItem(uint32 i)
3038 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3039 return;
3041 Player *player = (Player*)m_caster;
3043 // applied only to using item
3044 if(!m_CastItem)
3045 return;
3047 // ... only to item in own inventory/bank/equip_slot
3048 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3049 return;
3051 uint32 newitemid = m_spellInfo->EffectItemType[i];
3052 if(!newitemid)
3053 return;
3055 uint16 pos = m_CastItem->GetPos();
3057 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3058 if( !pNewItem )
3059 return;
3061 for(uint8 j= PERM_ENCHANTMENT_SLOT; j<=TEMP_ENCHANTMENT_SLOT; ++j)
3063 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
3064 pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
3067 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3069 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3070 player->DurabilityLoss(pNewItem, loosePercent);
3073 if( player->IsInventoryPos( pos ) )
3075 ItemPosCountVec dest;
3076 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3077 if( msg == EQUIP_ERR_OK )
3079 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3081 // prevent crash at access and unexpected charges counting with item update queue corrupt
3082 if(m_CastItem==m_targets.getItemTarget())
3083 m_targets.setItemTarget(NULL);
3085 m_CastItem = NULL;
3087 player->StoreItem( dest, pNewItem, true);
3088 return;
3091 else if( player->IsBankPos ( pos ) )
3093 ItemPosCountVec dest;
3094 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3095 if( msg == EQUIP_ERR_OK )
3097 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3099 // prevent crash at access and unexpected charges counting with item update queue corrupt
3100 if(m_CastItem==m_targets.getItemTarget())
3101 m_targets.setItemTarget(NULL);
3103 m_CastItem = NULL;
3105 player->BankItem( dest, pNewItem, true);
3106 return;
3109 else if( player->IsEquipmentPos ( pos ) )
3111 uint16 dest;
3112 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3113 if( msg == EQUIP_ERR_OK )
3115 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3117 // prevent crash at access and unexpected charges counting with item update queue corrupt
3118 if(m_CastItem==m_targets.getItemTarget())
3119 m_targets.setItemTarget(NULL);
3121 m_CastItem = NULL;
3123 player->EquipItem( dest, pNewItem, true);
3124 player->AutoUnequipOffhandIfNeed();
3125 return;
3129 // fail
3130 delete pNewItem;
3133 void Spell::EffectOpenSecretSafe(uint32 i)
3135 EffectOpenLock(i); //no difference for now
3138 void Spell::EffectProficiency(uint32 /*i*/)
3140 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3141 return;
3142 Player *p_target = (Player*)unitTarget;
3144 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3145 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3147 p_target->AddWeaponProficiency(subClassMask);
3148 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3150 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3152 p_target->AddArmorProficiency(subClassMask);
3153 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3157 void Spell::EffectApplyAreaAura(uint32 i)
3159 if(!unitTarget)
3160 return;
3161 if(!unitTarget->isAlive())
3162 return;
3164 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3165 unitTarget->AddAura(Aur);
3168 void Spell::EffectSummonType(uint32 i)
3170 switch(m_spellInfo->EffectMiscValueB[i])
3172 case SUMMON_TYPE_GUARDIAN:
3173 case SUMMON_TYPE_POSESSED:
3174 case SUMMON_TYPE_POSESSED2:
3175 case SUMMON_TYPE_FORCE_OF_NATURE:
3176 case SUMMON_TYPE_GUARDIAN2:
3177 EffectSummonGuardian(i);
3178 break;
3179 case SUMMON_TYPE_WILD:
3180 EffectSummonWild(i);
3181 break;
3182 case SUMMON_TYPE_DEMON:
3183 EffectSummonDemon(i);
3184 break;
3185 case SUMMON_TYPE_SUMMON:
3186 EffectSummon(i);
3187 break;
3188 case SUMMON_TYPE_CRITTER:
3189 case SUMMON_TYPE_CRITTER2:
3190 case SUMMON_TYPE_CRITTER3:
3191 EffectSummonCritter(i);
3192 break;
3193 case SUMMON_TYPE_TOTEM_SLOT1:
3194 case SUMMON_TYPE_TOTEM_SLOT2:
3195 case SUMMON_TYPE_TOTEM_SLOT3:
3196 case SUMMON_TYPE_TOTEM_SLOT4:
3197 case SUMMON_TYPE_TOTEM:
3198 EffectSummonTotem(i);
3199 break;
3200 case SUMMON_TYPE_UNKNOWN1:
3201 case SUMMON_TYPE_UNKNOWN2:
3202 case SUMMON_TYPE_UNKNOWN3:
3203 case SUMMON_TYPE_UNKNOWN4:
3204 case SUMMON_TYPE_UNKNOWN5:
3205 break;
3206 default:
3207 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3208 break;
3212 void Spell::EffectSummon(uint32 i)
3214 if(m_caster->GetPetGUID())
3215 return;
3217 if(!unitTarget)
3218 return;
3219 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3220 if(!pet_entry)
3221 return;
3222 uint32 level = m_caster->getLevel();
3223 Pet* spawnCreature = new Pet(SUMMON_PET);
3225 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3227 // set timer for unsummon
3228 int32 duration = GetSpellDuration(m_spellInfo);
3229 if(duration > 0)
3230 spawnCreature->SetDuration(duration);
3232 return;
3235 Map *map = m_caster->GetMap();
3236 uint32 pet_number = objmgr.GeneratePetNumber();
3237 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_caster->GetPhaseMask(),
3238 m_spellInfo->EffectMiscValue[i], pet_number))
3240 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3241 delete spawnCreature;
3242 return;
3245 // Summon in dest location
3246 float x,y,z;
3247 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3249 x = m_targets.m_destX;
3250 y = m_targets.m_destY;
3251 z = m_targets.m_destZ;
3253 else
3254 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3256 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3258 if(!spawnCreature->IsPositionValid())
3260 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3261 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3262 delete spawnCreature;
3263 return;
3266 // set timer for unsummon
3267 int32 duration = GetSpellDuration(m_spellInfo);
3268 if(duration > 0)
3269 spawnCreature->SetDuration(duration);
3271 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3272 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3273 spawnCreature->setPowerType(POWER_MANA);
3274 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3275 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3276 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3277 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3278 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3279 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3280 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3281 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3282 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3284 spawnCreature->InitStatsForLevel(level);
3286 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3288 spawnCreature->AIM_Initialize();
3289 spawnCreature->InitPetCreateSpells();
3290 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3291 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3293 std::string name = m_caster->GetName();
3294 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3295 spawnCreature->SetName( name );
3297 map->Add((Creature*)spawnCreature);
3299 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3301 m_caster->SetPet(spawnCreature);
3302 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3303 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3304 ((Player*)m_caster)->PetSpellInitialize();
3308 void Spell::EffectLearnSpell(uint32 i)
3310 if(!unitTarget)
3311 return;
3313 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3315 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3316 EffectLearnPetSpell(i);
3318 return;
3321 Player *player = (Player*)unitTarget;
3323 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3324 player->learnSpell(spellToLearn,false);
3326 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3329 void Spell::EffectDispel(uint32 i)
3331 if(!unitTarget)
3332 return;
3334 // Fill possible dispell list
3335 std::vector <Aura *> dispel_list;
3337 // Create dispel mask by dispel type
3338 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3339 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3340 Unit::AuraMap const& auras = unitTarget->GetAuras();
3341 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3343 Aura *aur = (*itr).second;
3344 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3346 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3348 bool positive = true;
3349 if (!aur->IsPositive())
3350 positive = false;
3351 else
3352 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3354 // do not remove positive auras if friendly target
3355 // negative auras if non-friendly target
3356 if(positive == unitTarget->IsFriendlyTo(m_caster))
3357 continue;
3359 // Add aura to dispel list
3360 dispel_list.push_back(aur);
3363 // Ok if exist some buffs for dispel try dispel it
3364 if (!dispel_list.empty())
3366 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3367 std::list < uint32 > fail_list; // spell_id
3368 int32 list_size = dispel_list.size();
3369 // Dispell N = damage buffs (or while exist buffs for dispel)
3370 for (int32 count=0; count < damage && list_size > 0; ++count)
3372 // Random select buff for dispel
3373 Aura *aur = dispel_list[urand(0, list_size-1)];
3375 SpellEntry const* spellInfo = aur->GetSpellProto();
3376 // Base dispel chance
3377 // TODO: possible chance depend from spell level??
3378 int32 miss_chance = 0;
3379 // Apply dispel mod from aura caster
3380 if (Unit *caster = aur->GetCaster())
3382 if ( Player* modOwner = caster->GetSpellModOwner() )
3383 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3385 // Try dispel
3386 if (roll_chance_i(miss_chance))
3387 fail_list.push_back(aur->GetId());
3388 else
3389 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3390 // Remove buff from list for prevent doubles
3391 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3393 Aura *dispeled = *j;
3394 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3396 j = dispel_list.erase(j);
3397 --list_size;
3399 else
3400 ++j;
3403 // Send success log and really remove auras
3404 if (!success_list.empty())
3406 int32 count = success_list.size();
3407 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3408 data.append(unitTarget->GetPackGUID()); // Victim GUID
3409 data.append(m_caster->GetPackGUID()); // Caster GUID
3410 data << uint32(m_spellInfo->Id); // Dispell spell id
3411 data << uint8(0); // not used
3412 data << uint32(count); // count
3413 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3415 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3416 data << uint32(spellInfo->Id); // Spell Id
3417 data << uint8(0); // 0 - dispeled !=0 cleansed
3418 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3420 m_caster->SendMessageToSet(&data, true);
3422 // On succes dispel
3423 // Devour Magic
3424 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
3426 uint32 heal_spell = 0;
3427 switch (m_spellInfo->Id)
3429 case 19505: heal_spell = 19658; break;
3430 case 19731: heal_spell = 19732; break;
3431 case 19734: heal_spell = 19733; break;
3432 case 19736: heal_spell = 19735; break;
3433 case 27276: heal_spell = 27278; break;
3434 case 27277: heal_spell = 27279; break;
3435 default:
3436 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3437 break;
3439 if (heal_spell)
3440 m_caster->CastSpell(m_caster, heal_spell, true);
3443 // Send fail log to client
3444 if (!fail_list.empty())
3446 // Failed to dispell
3447 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3448 data << uint64(m_caster->GetGUID()); // Caster GUID
3449 data << uint64(unitTarget->GetGUID()); // Victim GUID
3450 data << uint32(m_spellInfo->Id); // Dispell spell id
3451 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3452 data << uint32(*j); // Spell Id
3453 m_caster->SendMessageToSet(&data, true);
3458 void Spell::EffectDualWield(uint32 /*i*/)
3460 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3461 ((Player*)unitTarget)->SetCanDualWield(true);
3464 void Spell::EffectPull(uint32 /*i*/)
3466 // TODO: create a proper pull towards distract spell center for distract
3467 sLog.outDebug("WORLD: Spell Effect DUMMY");
3470 void Spell::EffectDistract(uint32 /*i*/)
3472 // Check for possible target
3473 if (!unitTarget || unitTarget->isInCombat())
3474 return;
3476 // target must be OK to do this
3477 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3478 return;
3480 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3482 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3484 // For players just turn them
3485 WorldPacket data;
3486 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3487 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3488 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3490 else
3492 // Set creature Distracted, Stop it, And turn it
3493 unitTarget->SetOrientation(angle);
3494 unitTarget->StopMoving();
3495 unitTarget->GetMotionMaster()->MoveDistract(damage*IN_MILISECONDS);
3499 void Spell::EffectPickPocket(uint32 /*i*/)
3501 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3502 return;
3504 // victim must be creature and attackable
3505 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3506 return;
3508 // victim have to be alive and humanoid or undead
3509 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3511 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3513 if (chance > irand(0, 19))
3515 // Stealing successful
3516 //sLog.outDebug("Sending loot from pickpocket");
3517 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3519 else
3521 // Reveal action + get attack
3522 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3523 if (((Creature*)unitTarget)->AI())
3524 ((Creature*)unitTarget)->AI()->AttackedBy(m_caster);
3529 void Spell::EffectAddFarsight(uint32 i)
3531 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3532 int32 duration = GetSpellDuration(m_spellInfo);
3533 DynamicObject* dynObj = new DynamicObject;
3534 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))
3536 delete dynObj;
3537 return;
3539 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3540 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3541 m_caster->AddDynObject(dynObj);
3542 dynObj->GetMap()->Add(dynObj);
3543 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3544 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3547 void Spell::EffectSummonWild(uint32 i)
3549 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3550 if(!creature_entry)
3551 return;
3553 uint32 level = m_caster->getLevel();
3555 // level of creature summoned using engineering item based at engineering skill level
3556 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3558 ItemPrototype const *proto = m_CastItem->GetProto();
3559 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3561 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3562 if(skill202)
3564 level = skill202/5;
3569 // select center of summon position
3570 float center_x = m_targets.m_destX;
3571 float center_y = m_targets.m_destY;
3572 float center_z = m_targets.m_destZ;
3574 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3576 int32 amount = damage > 0 ? damage : 1;
3578 for(int32 count = 0; count < amount; ++count)
3580 float px, py, pz;
3581 // If dest location if present
3582 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3584 // Summon 1 unit in dest location
3585 if (count == 0)
3587 px = m_targets.m_destX;
3588 py = m_targets.m_destY;
3589 pz = m_targets.m_destZ;
3591 // Summon in random point all other units if location present
3592 else
3593 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3595 // Summon if dest location not present near caster
3596 else
3597 m_caster->GetClosePoint(px,py,pz,3.0f);
3599 int32 duration = GetSpellDuration(m_spellInfo);
3601 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3603 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3607 void Spell::EffectSummonGuardian(uint32 i)
3609 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3610 if(!pet_entry)
3611 return;
3613 // Jewelery statue case (totem like)
3614 if(m_spellInfo->SpellIconID==2056)
3616 EffectSummonTotem(i);
3617 return;
3620 // set timer for unsummon
3621 int32 duration = GetSpellDuration(m_spellInfo);
3623 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3624 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3625 // so this code hack in fact
3626 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3627 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3628 return; // find old guardian, ignore summon
3630 // in another case summon new
3631 uint32 level = m_caster->getLevel();
3633 // level of pet summoned using engineering item based at engineering skill level
3634 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3636 ItemPrototype const *proto = m_CastItem->GetProto();
3637 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3639 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3640 if(skill202)
3642 level = skill202/5;
3647 // select center of summon position
3648 float center_x = m_targets.m_destX;
3649 float center_y = m_targets.m_destY;
3650 float center_z = m_targets.m_destZ;
3652 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3654 int32 amount = damage > 0 ? damage : 1;
3656 for(int32 count = 0; count < amount; ++count)
3658 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3660 Map *map = m_caster->GetMap();
3661 uint32 pet_number = objmgr.GeneratePetNumber();
3662 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_caster->GetPhaseMask(),
3663 m_spellInfo->EffectMiscValue[i], pet_number))
3665 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3666 delete spawnCreature;
3667 return;
3670 float px, py, pz;
3671 // If dest location if present
3672 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3674 // Summon 1 unit in dest location
3675 if (count == 0)
3677 px = m_targets.m_destX;
3678 py = m_targets.m_destY;
3679 pz = m_targets.m_destZ;
3681 // Summon in random point all other units if location present
3682 else
3683 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3685 // Summon if dest location not present near caster
3686 else
3687 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3689 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3691 if(!spawnCreature->IsPositionValid())
3693 sLog.outError("Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3694 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3695 delete spawnCreature;
3696 return;
3699 if(duration > 0)
3700 spawnCreature->SetDuration(duration);
3702 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3703 spawnCreature->setPowerType(POWER_MANA);
3704 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3705 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3706 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3707 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3708 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3709 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3710 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3712 spawnCreature->InitStatsForLevel(level);
3713 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3715 spawnCreature->AIM_Initialize();
3717 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3718 ((Player*)m_caster)->AddGuardian(spawnCreature);
3720 map->Add((Creature*)spawnCreature);
3724 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3726 if(!unitTarget)
3727 return;
3729 if(unitTarget->isInFlight())
3730 return;
3732 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3734 float fx,fy,fz;
3735 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3737 unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster);
3740 void Spell::EffectLearnSkill(uint32 i)
3742 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3743 return;
3745 if(damage < 0)
3746 return;
3748 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3749 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3750 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3753 void Spell::EffectAddHonor(uint32 /*i*/)
3755 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3756 return;
3758 // not scale value for item based reward (/10 value expected)
3759 if(m_CastItem)
3761 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10);
3762 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow());
3763 return;
3766 // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
3767 if( damage <= 50)
3769 uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
3770 ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward);
3771 sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
3773 else
3775 //maybe we have correct honor_gain in damage already
3776 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3777 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3781 void Spell::EffectTradeSkill(uint32 /*i*/)
3783 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3784 return;
3785 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3786 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3787 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3790 void Spell::EffectEnchantItemPerm(uint32 effect_idx)
3792 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3793 return;
3794 if (!itemTarget)
3795 return;
3797 Player* p_caster = (Player*)m_caster;
3799 // not grow at item use at item case
3800 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3802 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3803 if (!enchant_id)
3804 return;
3806 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3807 if(!pEnchant)
3808 return;
3810 // item can be in trade slot and have owner diff. from caster
3811 Player* item_owner = itemTarget->GetOwner();
3812 if(!item_owner)
3813 return;
3815 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3817 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3818 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3819 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3820 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3823 // remove old enchanting before applying new if equipped
3824 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3826 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3828 // add new enchanting if equipped
3829 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3832 void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
3834 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3835 return;
3836 if (!itemTarget)
3837 return;
3839 Player* p_caster = (Player*)m_caster;
3841 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3842 if (!enchant_id)
3843 return;
3845 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3846 if(!pEnchant)
3847 return;
3849 // support only enchantings with add socket in this slot
3851 bool add_socket = false;
3852 for(int i = 0; i < 3; ++i)
3854 if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
3856 add_socket = true;
3857 break;
3860 if(!add_socket)
3862 sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.",
3863 m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
3864 return;
3868 // item can be in trade slot and have owner diff. from caster
3869 Player* item_owner = itemTarget->GetOwner();
3870 if(!item_owner)
3871 return;
3873 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3875 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3876 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3877 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3878 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3881 // remove old enchanting before applying new if equipped
3882 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
3884 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3886 // add new enchanting if equipped
3887 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
3890 void Spell::EffectEnchantItemTmp(uint32 i)
3892 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3893 return;
3895 Player* p_caster = (Player*)m_caster;
3897 if(!itemTarget)
3898 return;
3900 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3902 // Shaman Rockbiter Weapon
3903 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3905 int32 enchnting_damage = m_currentBasePoints[1]+1;
3907 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3908 // with already applied percent bonus from Elemental Weapons talent
3909 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3910 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3911 switch(enchnting_damage)
3913 // Rank 1
3914 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3915 // Rank 2
3916 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3917 case 5: enchant_id = 3025; break; // 20%
3918 // Rank 3
3919 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3920 case 7: enchant_id = 3027; break; // 20%
3921 // Rank 4
3922 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3923 case 10: enchant_id = 503; break; // 14%
3924 case 11: enchant_id = 3031; break; // 20%
3925 // Rank 5
3926 case 15: enchant_id = 3035; break; // 0%
3927 case 16: enchant_id = 1663; break; // 7%
3928 case 17: enchant_id = 3033; break; // 14%
3929 case 18: enchant_id = 3034; break; // 20%
3930 // Rank 6
3931 case 28: enchant_id = 3038; break; // 0%
3932 case 29: enchant_id = 683; break; // 7%
3933 case 31: enchant_id = 3036; break; // 14%
3934 case 33: enchant_id = 3037; break; // 20%
3935 // Rank 7
3936 case 40: enchant_id = 3041; break; // 0%
3937 case 42: enchant_id = 1664; break; // 7%
3938 case 45: enchant_id = 3039; break; // 14%
3939 case 48: enchant_id = 3040; break; // 20%
3940 // Rank 8
3941 case 49: enchant_id = 3044; break; // 0%
3942 case 52: enchant_id = 2632; break; // 7%
3943 case 55: enchant_id = 3042; break; // 14%
3944 case 58: enchant_id = 3043; break; // 20%
3945 // Rank 9
3946 case 62: enchant_id = 2633; break; // 0%
3947 case 66: enchant_id = 3018; break; // 7%
3948 case 70: enchant_id = 3019; break; // 14%
3949 case 74: enchant_id = 3020; break; // 20%
3950 default:
3951 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3952 return;
3956 if (!enchant_id)
3958 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3959 return;
3962 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3963 if(!pEnchant)
3965 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3966 return;
3969 // select enchantment duration
3970 uint32 duration;
3972 // rogue family enchantments exception by duration
3973 if(m_spellInfo->Id==38615)
3974 duration = 1800; // 30 mins
3975 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3976 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3977 duration = 3600; // 1 hour
3978 // shaman family enchantments
3979 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3980 duration = 1800; // 30 mins
3981 // other cases with this SpellVisual already selected
3982 else if(m_spellInfo->SpellVisual[0]==215)
3983 duration = 1800; // 30 mins
3984 // some fishing pole bonuses
3985 else if(m_spellInfo->SpellVisual[0]==563)
3986 duration = 600; // 10 mins
3987 // shaman rockbiter enchantments
3988 else if(m_spellInfo->SpellVisual[0]==0)
3989 duration = 1800; // 30 mins
3990 else if(m_spellInfo->Id==29702)
3991 duration = 300; // 5 mins
3992 else if(m_spellInfo->Id==37360)
3993 duration = 300; // 5 mins
3994 // default case
3995 else
3996 duration = 3600; // 1 hour
3998 // item can be in trade slot and have owner diff. from caster
3999 Player* item_owner = itemTarget->GetOwner();
4000 if(!item_owner)
4001 return;
4003 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
4005 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
4006 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
4007 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
4008 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
4011 // remove old enchanting before applying new if equipped
4012 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
4014 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
4016 // add new enchanting if equipped
4017 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
4020 void Spell::EffectTameCreature(uint32 /*i*/)
4022 if(m_caster->GetPetGUID())
4023 return;
4025 if(!unitTarget)
4026 return;
4028 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
4029 return;
4031 Creature* creatureTarget = (Creature*)unitTarget;
4033 if(creatureTarget->isPet())
4034 return;
4036 if(m_caster->getClass() != CLASS_HUNTER)
4037 return;
4039 // cast finish successfully
4040 //SendChannelUpdate(0);
4041 finish();
4043 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
4045 // kill original creature
4046 creatureTarget->setDeathState(JUST_DIED);
4047 creatureTarget->RemoveCorpse();
4048 creatureTarget->SetHealth(0); // just for nice GM-mode view
4050 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4052 // prepare visual effect for levelup
4053 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4055 // add to world
4056 pet->GetMap()->Add((Creature*)pet);
4058 // visual effect for levelup
4059 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4061 // caster have pet now
4062 m_caster->SetPet(pet);
4064 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4066 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4067 ((Player*)m_caster)->PetSpellInitialize();
4071 void Spell::EffectSummonPet(uint32 i)
4073 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4075 Pet *OldSummon = m_caster->GetPet();
4077 // if pet requested type already exist
4078 if( OldSummon )
4080 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4082 // pet in corpse state can't be summoned
4083 if( OldSummon->isDead() )
4084 return;
4086 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4087 OldSummon->SetMapId(m_caster->GetMapId());
4089 float px, py, pz;
4090 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4092 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4093 m_caster->GetMap()->Add((Creature*)OldSummon);
4095 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4097 ((Player*)m_caster)->PetSpellInitialize();
4099 return;
4102 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4103 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4104 else
4105 return;
4108 Pet* NewSummon = new Pet;
4110 // petentry==0 for hunter "call pet" (current pet summoned if any)
4111 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4113 if(NewSummon->getPetType()==SUMMON_PET)
4115 // Remove Demonic Sacrifice auras (known pet)
4116 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4117 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4119 if((*itr)->GetModifier()->m_miscvalue==2228)
4121 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4122 itr = auraClassScripts.begin();
4124 else
4125 ++itr;
4129 return;
4132 // not error in case fail hunter call pet
4133 if(!petentry)
4135 delete NewSummon;
4136 return;
4139 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4141 if(!cInfo)
4143 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4144 delete NewSummon;
4145 return;
4148 Map *map = m_caster->GetMap();
4149 uint32 pet_number = objmgr.GeneratePetNumber();
4150 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
4151 petentry, pet_number))
4153 delete NewSummon;
4154 return;
4157 float px, py, pz;
4158 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4160 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4162 if(!NewSummon->IsPositionValid())
4164 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4165 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4166 delete NewSummon;
4167 return;
4170 uint32 petlevel = m_caster->getLevel();
4171 NewSummon->setPetType(SUMMON_PET);
4173 uint32 faction = m_caster->getFaction();
4174 if(m_caster->GetTypeId() == TYPEID_UNIT)
4176 if ( ((Creature*)m_caster)->isTotem() )
4177 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4178 else
4179 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4182 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4183 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4184 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4185 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4186 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4187 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4188 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4189 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4190 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4191 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4193 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4194 // this enables pet details window (Shift+P)
4196 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4197 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4198 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4200 NewSummon->InitStatsForLevel(petlevel);
4201 NewSummon->InitPetCreateSpells();
4202 NewSummon->InitTalentForLevel();
4204 if(NewSummon->getPetType()==SUMMON_PET)
4206 // Remove Demonic Sacrifice auras (new pet)
4207 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4208 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4210 if((*itr)->GetModifier()->m_miscvalue==2228)
4212 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4213 itr = auraClassScripts.begin();
4215 else
4216 ++itr;
4219 // generate new name for summon pet
4220 std::string new_name=objmgr.GeneratePetName(petentry);
4221 if(!new_name.empty())
4222 NewSummon->SetName(new_name);
4224 else if(NewSummon->getPetType()==HUNTER_PET)
4225 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4227 NewSummon->AIM_Initialize();
4228 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4229 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4231 map->Add((Creature*)NewSummon);
4233 m_caster->SetPet(NewSummon);
4234 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4236 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4238 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4239 ((Player*)m_caster)->PetSpellInitialize();
4243 void Spell::EffectLearnPetSpell(uint32 i)
4245 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4246 return;
4248 Player *_player = (Player*)m_caster;
4250 Pet *pet = _player->GetPet();
4251 if(!pet)
4252 return;
4253 if(!pet->isAlive())
4254 return;
4256 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4257 if(!learn_spellproto)
4258 return;
4260 pet->learnSpell(learn_spellproto->Id);
4262 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4263 _player->PetSpellInitialize();
4266 void Spell::EffectTaunt(uint32 /*i*/)
4268 if (!unitTarget)
4269 return;
4271 // this effect use before aura Taunt apply for prevent taunt already attacking target
4272 // for spell as marked "non effective at already attacking target"
4273 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
4275 if (unitTarget->getVictim()==m_caster)
4277 SendCastResult(SPELL_FAILED_DONT_REPORT);
4278 return;
4282 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4283 if (unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4284 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4287 void Spell::EffectWeaponDmg(uint32 i)
4289 if(!unitTarget)
4290 return;
4291 if(!unitTarget->isAlive())
4292 return;
4294 // multiple weapon dmg effect workaround
4295 // execute only the last weapon damage
4296 // and handle all effects at once
4297 for (int j = 0; j < 3; j++)
4299 switch(m_spellInfo->Effect[j])
4301 case SPELL_EFFECT_WEAPON_DAMAGE:
4302 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4303 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4304 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4305 if (j < i) // we must calculate only at last weapon effect
4306 return;
4307 break;
4311 // some spell specific modifiers
4312 bool spellBonusNeedWeaponDamagePercentMod = false; // if set applied weapon damage percent mode to spell bonus
4314 float weaponDamagePercentMod = 1.0f; // applied to weapon damage and to fixed effect damage bonus
4315 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4316 bool normalized = false;
4318 int32 spell_bonus = 0; // bonus specific for spell
4319 switch(m_spellInfo->SpellFamilyName)
4321 case SPELLFAMILY_WARRIOR:
4323 // Whirlwind, single only spell with 2 weapon white damage apply if have
4324 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4326 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4327 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4329 // Devastate bonus and sunder armor refresh
4330 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4332 uint32 stack = 0;
4333 // Need refresh all Sunder Armor auras from this caster
4334 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4335 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4337 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4338 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4339 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4340 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4342 (*itr).second->RefreshAura();
4343 stack = (*itr).second->GetStackAmount();
4346 if (stack)
4347 spell_bonus += stack * CalculateDamage(2, unitTarget);
4349 break;
4351 case SPELLFAMILY_ROGUE:
4353 // Mutilate (for each hand)
4354 if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4356 bool found = false;
4357 // fast check
4358 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4359 found = true;
4360 // full aura scan
4361 else
4363 Unit::AuraMap const& auras = unitTarget->GetAuras();
4364 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4366 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4368 found = true;
4369 break;
4374 if(found)
4375 totalDamagePercentMod *= 1.2f; // 120% if poisoned
4377 break;
4379 case SPELLFAMILY_PALADIN:
4381 // Seal of Command - receive benefit from Spell Damage and Healing
4382 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4384 spellBonusNeedWeaponDamagePercentMod = true;// apply weaponDamagePercentMod to spell_bonus (and then to all bonus, fixes and weapon already have applied)
4385 spell_bonus += int32(0.23f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4386 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4388 break;
4390 case SPELLFAMILY_SHAMAN:
4392 // Skyshatter Harness item set bonus
4393 // Stormstrike
4394 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4396 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4397 for(Unit::AuraList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr)
4399 // Stormstrike AP Buff
4400 if ( (*citr)->GetModifier()->m_miscvalue == 5634 )
4402 m_caster->CastSpell(m_caster,38430,true,NULL,*citr);
4403 break;
4410 int32 fixed_bonus = 0;
4411 for (int j = 0; j < 3; j++)
4413 switch(m_spellInfo->Effect[j])
4415 case SPELL_EFFECT_WEAPON_DAMAGE:
4416 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4417 fixed_bonus += CalculateDamage(j,unitTarget);
4418 break;
4419 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4420 fixed_bonus += CalculateDamage(j,unitTarget);
4421 normalized = true;
4422 break;
4423 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4424 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4426 // applied only to prev.effects fixed damage
4427 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4428 break;
4429 default:
4430 break; // not weapon damage effect, just skip
4434 // apply weaponDamagePercentMod to spell bonus also
4435 if(spellBonusNeedWeaponDamagePercentMod)
4436 spell_bonus = int32(spell_bonus*weaponDamagePercentMod);
4438 // non-weapon damage
4439 int32 bonus = spell_bonus + fixed_bonus;
4441 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4442 if(bonus)
4444 UnitMods unitMod;
4445 switch(m_attackType)
4447 default:
4448 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4449 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4450 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4453 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4454 bonus = int32(bonus*weapon_total_pct);
4457 // + weapon damage with applied weapon% dmg to base weapon damage in call
4458 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4460 // total damage
4461 bonus = int32(bonus*totalDamagePercentMod);
4463 // prevent negative damage
4464 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4466 // Add melee damage bonuses (also check for negative)
4467 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4468 m_damage+= eff_damage;
4470 // Hemorrhage
4471 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4473 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4474 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4477 // Mangle (Cat): CP
4478 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4480 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4481 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4484 // take ammo
4485 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4487 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4489 // wands don't have ammo
4490 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4491 return;
4493 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4495 if(pItem->GetMaxStackCount()==1)
4497 // decrease durability for non-stackable throw weapon
4498 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4500 else
4502 // decrease items amount for stackable throw weapon
4503 uint32 count = 1;
4504 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4507 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4508 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4512 void Spell::EffectThreat(uint32 /*i*/)
4514 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4515 return;
4517 if(!unitTarget->CanHaveThreatList())
4518 return;
4520 unitTarget->AddThreat(m_caster, float(damage));
4523 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4525 if(!unitTarget)
4526 return;
4527 if(!unitTarget->isAlive())
4528 return;
4530 uint32 heal = m_caster->GetMaxHealth();
4532 m_healing+=heal;
4535 void Spell::EffectInterruptCast(uint32 /*i*/)
4537 if(!unitTarget)
4538 return;
4539 if(!unitTarget->isAlive())
4540 return;
4542 // TODO: not all spells that used this effect apply cooldown at school spells
4543 // also exist case: apply cooldown to interrupted cast only and to all spells
4544 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4546 if (unitTarget->m_currentSpells[i])
4548 // check if we can interrupt spell
4549 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4551 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4552 unitTarget->InterruptSpell(i,false);
4558 void Spell::EffectSummonObjectWild(uint32 i)
4560 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4562 GameObject* pGameObj = new GameObject;
4564 WorldObject* target = focusObject;
4565 if( !target )
4566 target = m_caster;
4568 float x,y,z;
4569 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4571 x = m_targets.m_destX;
4572 y = m_targets.m_destY;
4573 z = m_targets.m_destZ;
4575 else
4576 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4578 Map *map = target->GetMap();
4580 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4581 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
4583 delete pGameObj;
4584 return;
4587 int32 duration = GetSpellDuration(m_spellInfo);
4588 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4589 pGameObj->SetSpellId(m_spellInfo->Id);
4591 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4592 m_caster->AddGameObject(pGameObj);
4593 map->Add(pGameObj);
4595 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4597 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4599 Player *pl = (Player*)m_caster;
4600 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4601 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4603 uint32 team = ALLIANCE;
4605 if(pl->GetTeam() == team)
4606 team = HORDE;
4608 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4613 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4615 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4617 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4618 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4620 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4625 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4627 GameObject* linkedGO = new GameObject;
4628 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4629 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
4631 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4632 linkedGO->SetSpellId(m_spellInfo->Id);
4634 m_caster->AddGameObject(linkedGO);
4635 map->Add(linkedGO);
4637 else
4639 delete linkedGO;
4640 linkedGO = NULL;
4641 return;
4646 void Spell::EffectScriptEffect(uint32 effIndex)
4648 // TODO: we must implement hunter pet summon at login there (spell 6962)
4650 switch(m_spellInfo->SpellFamilyName)
4652 case SPELLFAMILY_GENERIC:
4654 switch(m_spellInfo->Id)
4656 // PX-238 Winter Wondervolt TRAP
4657 case 26275:
4659 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4661 // check presence
4662 for(int j = 0; j < 4; ++j)
4663 if(unitTarget->HasAura(spells[j],0))
4664 return;
4666 // select spell
4667 uint32 iTmpSpellId = spells[urand(0,3)];
4669 // cast
4670 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4671 return;
4673 // Bending Shinbone
4674 case 8856:
4676 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4677 return;
4679 uint32 spell_id = 0;
4680 switch(urand(1,5))
4682 case 1: spell_id = 8854; break;
4683 default: spell_id = 8855; break;
4686 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4687 return;
4689 // Brittle Armor - need remove one 24575 Brittle Armor aura
4690 case 24590:
4691 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4692 return;
4693 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4694 case 26465:
4695 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4696 return;
4697 // Orb teleport spells
4698 case 25140:
4699 case 25143:
4700 case 25650:
4701 case 25652:
4702 case 29128:
4703 case 29129:
4704 case 35376:
4705 case 35727:
4707 if(!unitTarget)
4708 return;
4710 uint32 spellid;
4711 switch(m_spellInfo->Id)
4713 case 25140: spellid = 32571; break;
4714 case 25143: spellid = 32572; break;
4715 case 25650: spellid = 30140; break;
4716 case 25652: spellid = 30141; break;
4717 case 29128: spellid = 32568; break;
4718 case 29129: spellid = 32569; break;
4719 case 35376: spellid = 25649; break;
4720 case 35727: spellid = 35730; break;
4721 default:
4722 return;
4725 unitTarget->CastSpell(unitTarget,spellid,false);
4726 return;
4728 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4729 case 22539:
4730 case 22972:
4731 case 22975:
4732 case 22976:
4733 case 22977:
4734 case 22978:
4735 case 22979:
4736 case 22980:
4737 case 22981:
4738 case 22982:
4739 case 22983:
4740 case 22984:
4741 case 22985:
4743 if(!unitTarget || !unitTarget->isAlive())
4744 return;
4746 // Onyxia Scale Cloak
4747 if(unitTarget->GetDummyAura(22683))
4748 return;
4750 // Shadow Flame
4751 m_caster->CastSpell(unitTarget, 22682, true);
4752 return;
4754 // Summon Black Qiraji Battle Tank
4755 case 26656:
4757 if(!unitTarget)
4758 return;
4760 // Prevent stacking of mounts
4761 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4763 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4764 if (unitTarget->GetAreaId() == 3428)
4765 unitTarget->CastSpell(unitTarget, 25863, false);
4766 else
4767 unitTarget->CastSpell(unitTarget, 26655, false);
4768 return;
4770 // Piccolo of the Flaming Fire
4771 case 17512:
4773 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4774 return;
4775 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4776 return;
4778 // Escape artist
4779 case 20589:
4781 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4782 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
4783 return;
4785 // Mirren's Drinking Hat
4786 case 29830:
4788 uint32 item = 0;
4789 switch ( urand(1,6) )
4791 case 1:case 2:case 3:
4792 item = 23584;break; // Loch Modan Lager
4793 case 4:case 5:
4794 item = 23585;break; // Stouthammer Lite
4795 case 6:
4796 item = 23586;break; // Aerie Peak Pale Ale
4798 if (item)
4799 DoCreateItem(effIndex,item);
4800 break;
4802 // Improved Sprint
4803 case 30918:
4805 // Removes snares and roots.
4806 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4807 Unit::AuraMap& Auras = unitTarget->GetAuras();
4808 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4810 next = iter;
4811 ++next;
4812 Aura *aur = iter->second;
4813 if (!aur->IsPositive()) //only remove negative spells
4815 // check for mechanic mask
4816 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4818 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4819 if(Auras.empty())
4820 break;
4821 else
4822 next = Auras.begin();
4826 break;
4828 // Flame Crash
4829 case 41126:
4831 if(!unitTarget)
4832 return;
4834 unitTarget->CastSpell(unitTarget, 41131, true);
4835 break;
4837 // Force Cast - Portal Effect: Sunwell Isle
4838 case 44876:
4840 if(!unitTarget)
4841 return;
4843 unitTarget->CastSpell(unitTarget, 44870, true);
4844 break;
4846 // Goblin Weather Machine
4847 case 46203:
4849 if(!unitTarget)
4850 return;
4852 uint32 spellId = 0;
4853 switch(rand()%4)
4855 case 0: spellId = 46740; break;
4856 case 1: spellId = 46739; break;
4857 case 2: spellId = 46738; break;
4858 case 3: spellId = 46736; break;
4860 unitTarget->CastSpell(unitTarget, spellId, true);
4861 break;
4863 //5,000 Gold
4864 case 46642:
4866 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4867 return;
4869 ((Player*)unitTarget)->ModifyMoney(50000000);
4871 break;
4873 // Emblazon Runeblade
4874 case 51770:
4876 if(!unitTarget)
4877 return;
4879 unitTarget->CastSpell(unitTarget,51771,false);
4880 break;
4882 // Death Gate
4883 case 52751:
4885 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4886 return;
4887 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4888 unitTarget->CastSpell(unitTarget, damage, false);
4889 break;
4891 // Winged Steed of the Ebon Blade
4892 case 54729:
4894 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4895 return;
4897 // Prevent stacking of mounts
4898 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4900 // Triggered spell id dependent of riding skill
4901 if(uint16 skillval = ((Player*)unitTarget)->GetSkillValue(SKILL_RIDING))
4903 if (skillval >= 300)
4904 unitTarget->CastSpell(unitTarget, 54727, true);
4905 else
4906 unitTarget->CastSpell(unitTarget, 54726, true);
4908 return;
4910 case 58418: // Portal to Orgrimmar
4911 case 58420: // Portal to Stormwind
4913 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex!=0)
4914 return;
4916 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
4917 uint32 questID = m_spellInfo->CalculateSimpleValue(1);
4919 if (((Player*)unitTarget)->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !((Player*)unitTarget)->GetQuestRewardStatus (questID))
4920 unitTarget->CastSpell(unitTarget, spellID, true);
4922 return;
4924 case 59317: // Teleporting
4925 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4926 return;
4928 // return from top
4929 if (((Player*)unitTarget)->GetAreaId() == 4637)
4930 unitTarget->CastSpell(unitTarget, 59316, true);
4931 // teleport atop
4932 else
4933 unitTarget->CastSpell(unitTarget, 59314, true);
4935 return;
4936 // random spell learn instead placeholder
4937 case 60893: // Northrend Alchemy Research
4938 case 61177: // Northrend Inscription Research
4939 case 61288: // Minor Inscription Research
4940 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4942 if(!IsExplicitDiscoverySpell(m_spellInfo))
4944 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4945 return;
4948 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4949 return;
4950 Player* player = (Player*)m_caster;
4952 // need replace effect 0 item by loot
4953 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4955 if(!player->HasItemCount(reagent_id,1))
4956 return;
4958 // remove reagent
4959 uint32 count = 1;
4960 player->DestroyItemCount (reagent_id,count,true);
4962 // create some random items
4963 player->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
4965 // learn random explicit discovery recipe (if any)
4966 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4967 player->learnSpell(discoveredSpell,false);
4968 return;
4971 break;
4973 case SPELLFAMILY_WARLOCK:
4975 switch(m_spellInfo->Id)
4977 // Healthstone creating spells
4978 case 6201:
4979 case 6202:
4980 case 5699:
4981 case 11729:
4982 case 11730:
4983 case 27230:
4984 case 47871:
4985 case 47878:
4987 uint32 itemtype;
4988 uint32 rank = 0;
4989 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4990 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4992 if((*i)->GetId() == 18692)
4994 rank = 1;
4995 break;
4997 else if((*i)->GetId() == 18693)
4999 rank = 2;
5000 break;
5004 static uint32 const itypes[8][3] = {
5005 { 5512,19004,19005}, // Minor Healthstone
5006 { 5511,19006,19007}, // Lesser Healthstone
5007 { 5509,19008,19009}, // Healthstone
5008 { 5510,19010,19011}, // Greater Healthstone
5009 { 9421,19012,19013}, // Major Healthstone
5010 {22103,22104,22105}, // Master Healthstone
5011 {36889,36890,36891}, // Demonic Healthstone
5012 {36892,36893,36894} // Fel Healthstone
5015 switch(m_spellInfo->Id)
5017 case 6201:
5018 itemtype=itypes[0][rank];break; // Minor Healthstone
5019 case 6202:
5020 itemtype=itypes[1][rank];break; // Lesser Healthstone
5021 case 5699:
5022 itemtype=itypes[2][rank];break; // Healthstone
5023 case 11729:
5024 itemtype=itypes[3][rank];break; // Greater Healthstone
5025 case 11730:
5026 itemtype=itypes[4][rank];break; // Major Healthstone
5027 case 27230:
5028 itemtype=itypes[5][rank];break; // Master Healthstone
5029 case 47871:
5030 itemtype=itypes[6][rank];break; // Demonic Healthstone
5031 case 47878:
5032 itemtype=itypes[7][rank];break; // Fel Healthstone
5033 default:
5034 return;
5036 DoCreateItem( effIndex, itemtype );
5037 return;
5039 // Everlasting Affliction
5040 case 47422:
5042 // Need refresh caster corruption auras on target
5043 Unit::AuraMap& suAuras = unitTarget->GetAuras();
5044 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
5046 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5047 if(spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK &&
5048 spellInfo->SpellFamilyFlags & 0x0000000000000002LL &&
5049 (*itr).second->GetCasterGUID()==m_caster->GetGUID())
5050 (*itr).second->RefreshAura();
5052 return;
5055 break;
5057 case SPELLFAMILY_PRIEST:
5059 switch(m_spellInfo->Id)
5061 // Pain and Suffering
5062 case 47948:
5064 if (!unitTarget)
5065 return;
5066 // Refresh Shadow Word: Pain on target
5067 Unit::AuraMap& auras = unitTarget->GetAuras();
5068 for(Unit::AuraMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
5070 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5071 if( spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST &&
5072 spellInfo->SpellFamilyFlags & 0x0000000000008000LL &&
5073 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
5075 (*itr).second->RefreshAura();
5076 return;
5079 return;
5081 default:
5082 break;
5084 break;
5086 case SPELLFAMILY_HUNTER:
5088 switch(m_spellInfo->Id)
5090 // Chimera Shot
5091 case 53209:
5093 uint32 spellId = 0;
5094 int32 basePoint = 0;
5095 Unit::AuraMap& Auras = unitTarget->GetAuras();
5096 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
5098 Aura *aura = (*i).second;
5099 if (aura->GetCasterGUID() != m_caster->GetGUID())
5100 continue;
5101 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
5102 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
5103 if (!(familyFlag & 0x000000800000C000LL))
5104 continue;
5105 // Refresh aura duration
5106 aura->RefreshAura();
5108 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
5109 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
5111 spellId = 53353; // 53353 Chimera Shot - Serpent
5112 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
5114 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
5115 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
5117 spellId = 53358; // 53358 Chimera Shot - Viper
5118 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
5120 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
5121 if (familyFlag & 0x0000000000008000LL)
5122 spellId = 53359; // 53359 Chimera Shot - Scorpid
5123 // ?? nothing say in spell desc (possibly need addition check)
5124 //if (familyFlag & 0x0000010000000000LL || // dot
5125 // familyFlag & 0x0000100000000000LL) // stun
5127 // spellId = 53366; // 53366 Chimera Shot - Wyvern
5130 if (spellId)
5131 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
5132 return;
5134 default:
5135 break;
5137 break;
5139 case SPELLFAMILY_PALADIN:
5141 // Judgement
5142 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5144 if(!unitTarget || !unitTarget->isAlive())
5145 return;
5146 uint32 spellId1 = 0;
5147 uint32 spellId2 = 0;
5149 // Judgement self add switch
5150 switch (m_spellInfo->Id)
5152 case 41467: break; // Judgement
5153 case 53407: spellId1 = 20184; break; // Judgement of Justice
5154 case 20271: // Judgement of Light
5155 case 57774: spellId1 = 20185; break; // Judgement of Light
5156 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5157 default:
5158 return;
5160 // all seals have aura dummy in 2 effect
5161 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5162 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5164 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5165 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5166 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5167 continue;
5168 spellId2 = (*itr)->GetModifier()->m_amount;
5169 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5170 if (!judge)
5171 continue;
5172 break;
5174 if (spellId1)
5175 m_caster->CastSpell(unitTarget, spellId1, true);
5176 if (spellId2)
5177 m_caster->CastSpell(unitTarget, spellId2, true);
5178 return;
5181 case SPELLFAMILY_POTION:
5183 switch(m_spellInfo->Id)
5185 // Dreaming Glory
5186 case 28698:
5188 if(!unitTarget)
5189 return;
5190 unitTarget->CastSpell(unitTarget, 28694, true);
5191 break;
5193 // Netherbloom
5194 case 28702:
5196 if(!unitTarget)
5197 return;
5198 // 25% chance of casting a random buff
5199 if(roll_chance_i(75))
5200 return;
5202 // triggered spells are 28703 to 28707
5203 // Note: some sources say, that there was the possibility of
5204 // receiving a debuff. However, this seems to be removed by a patch.
5205 const uint32 spellid = 28703;
5207 // don't overwrite an existing aura
5208 for(uint8 i=0; i<5; i++)
5209 if(unitTarget->HasAura(spellid+i, 0))
5210 return;
5211 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5212 break;
5215 // Nightmare Vine
5216 case 28720:
5218 if(!unitTarget)
5219 return;
5220 // 25% chance of casting Nightmare Pollen
5221 if(roll_chance_i(75))
5222 return;
5223 unitTarget->CastSpell(unitTarget, 28721, true);
5224 break;
5227 break;
5231 // normal DB scripted effect
5232 if(!unitTarget)
5233 return;
5235 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5236 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5239 void Spell::EffectSanctuary(uint32 /*i*/)
5241 if(!unitTarget)
5242 return;
5243 //unitTarget->CombatStop();
5245 unitTarget->CombatStop();
5246 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5247 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5248 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5250 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5254 void Spell::EffectAddComboPoints(uint32 /*i*/)
5256 if(!unitTarget)
5257 return;
5259 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5260 return;
5262 if(damage <= 0)
5263 return;
5265 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5268 void Spell::EffectDuel(uint32 i)
5270 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5271 return;
5273 Player *caster = (Player*)m_caster;
5274 Player *target = (Player*)unitTarget;
5276 // caster or target already have requested duel
5277 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5278 return;
5280 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5281 // Don't have to check the target's map since you cannot challenge someone across maps
5282 uint32 mapid = caster->GetMapId();
5283 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5285 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5286 return;
5289 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5290 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5292 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5293 return;
5296 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5297 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5299 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5300 return;
5303 //CREATE DUEL FLAG OBJECT
5304 GameObject* pGameObj = new GameObject;
5306 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5308 Map *map = m_caster->GetMap();
5309 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
5310 map, m_caster->GetPhaseMask(),
5311 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5312 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5313 m_caster->GetPositionZ(),
5314 m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
5316 delete pGameObj;
5317 return;
5320 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5321 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5322 int32 duration = GetSpellDuration(m_spellInfo);
5323 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5324 pGameObj->SetSpellId(m_spellInfo->Id);
5326 m_caster->AddGameObject(pGameObj);
5327 map->Add(pGameObj);
5328 //END
5330 // Send request
5331 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5332 data << pGameObj->GetGUID();
5333 data << caster->GetGUID();
5334 caster->GetSession()->SendPacket(&data);
5335 target->GetSession()->SendPacket(&data);
5337 // create duel-info
5338 DuelInfo *duel = new DuelInfo;
5339 duel->initiator = caster;
5340 duel->opponent = target;
5341 duel->startTime = 0;
5342 duel->startTimer = 0;
5343 caster->duel = duel;
5345 DuelInfo *duel2 = new DuelInfo;
5346 duel2->initiator = caster;
5347 duel2->opponent = caster;
5348 duel2->startTime = 0;
5349 duel2->startTimer = 0;
5350 target->duel = duel2;
5352 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5353 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5356 void Spell::EffectStuck(uint32 /*i*/)
5358 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5359 return;
5361 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5362 return;
5364 Player* pTarget = (Player*)unitTarget;
5366 sLog.outDebug("Spell Effect: Stuck");
5367 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());
5369 if(pTarget->isInFlight())
5370 return;
5372 // homebind location is loaded always
5373 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5375 // Stuck spell trigger Hearthstone cooldown
5376 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5377 if(!spellInfo)
5378 return;
5379 Spell spell(pTarget,spellInfo,true,0);
5380 spell.SendSpellCooldown();
5383 void Spell::EffectSummonPlayer(uint32 /*i*/)
5385 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5386 return;
5388 // Evil Twin (ignore player summon, but hide this for summoner)
5389 if(unitTarget->GetDummyAura(23445))
5390 return;
5392 float x,y,z;
5393 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5395 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5397 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5398 data << uint64(m_caster->GetGUID()); // summoner guid
5399 data << uint32(m_caster->GetZoneId()); // summoner zone
5400 data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILISECONDS); // auto decline after msecs
5401 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5404 static ScriptInfo generateActivateCommand()
5406 ScriptInfo si;
5407 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5408 return si;
5411 void Spell::EffectActivateObject(uint32 effect_idx)
5413 if(!gameObjTarget)
5414 return;
5416 static ScriptInfo activateCommand = generateActivateCommand();
5418 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5420 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5423 void Spell::EffectApplyGlyph(uint32 i)
5425 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5426 return;
5428 Player *player = (Player*)m_caster;
5430 // apply new one
5431 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5433 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5435 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5437 if(gp->TypeFlags != gs->TypeFlags)
5439 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5440 return; // glyph slot mismatch
5444 // remove old glyph
5445 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5447 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5449 player->RemoveAurasDueToSpell(old_gp->SpellId);
5450 player->SetGlyph(m_glyphIndex, 0);
5454 player->CastSpell(m_caster, gp->SpellId, true);
5455 player->SetGlyph(m_glyphIndex, glyph);
5460 void Spell::EffectSummonTotem(uint32 i)
5462 uint8 slot = 0;
5463 switch(m_spellInfo->EffectMiscValueB[i])
5465 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5466 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5467 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5468 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5469 // Battle standard case
5470 case SUMMON_TYPE_TOTEM: slot = 254; break;
5471 // jewelery statue case, like totem without slot
5472 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5473 default: return;
5476 if(slot < MAX_TOTEM)
5478 uint64 guid = m_caster->m_TotemSlot[slot];
5479 if(guid != 0)
5481 Creature *OldTotem = m_caster->GetMap()->GetCreature(guid);
5482 if(OldTotem && OldTotem->isTotem())
5483 ((Totem*)OldTotem)->UnSummon();
5487 uint32 team = 0;
5488 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5489 team = ((Player*)m_caster)->GetTeam();
5491 Totem* pTotem = new Totem;
5493 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
5494 m_spellInfo->EffectMiscValue[i], team ))
5496 delete pTotem;
5497 return;
5500 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5502 float x,y,z;
5503 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5505 // totem must be at same Z in case swimming caster and etc.
5506 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5507 z = m_caster->GetPositionZ();
5509 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5511 if(slot < MAX_TOTEM)
5512 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5514 pTotem->SetOwner(m_caster->GetGUID());
5515 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5517 int32 duration=GetSpellDuration(m_spellInfo);
5518 if(Player* modOwner = m_caster->GetSpellModOwner())
5519 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5520 pTotem->SetDuration(duration);
5522 if (damage) // if not spell info, DB values used
5524 pTotem->SetMaxHealth(damage);
5525 pTotem->SetHealth(damage);
5528 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5530 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5531 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5533 pTotem->Summon(m_caster);
5535 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5537 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5538 data << uint8(slot);
5539 data << uint64(pTotem->GetGUID());
5540 data << uint32(duration);
5541 data << uint32(m_spellInfo->Id);
5542 ((Player*)m_caster)->SendDirectMessage(&data);
5546 void Spell::EffectEnchantHeldItem(uint32 i)
5548 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5549 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5550 return;
5552 Player* item_owner = (Player*)unitTarget;
5553 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5555 if(!item )
5556 return;
5558 // must be equipped
5559 if(!item ->IsEquipped())
5560 return;
5562 if (m_spellInfo->EffectMiscValue[i])
5564 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5565 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5566 if(!duration)
5567 duration = m_currentBasePoints[i]+1; //Base points after ..
5568 if(!duration)
5569 duration = 10; //10 seconds for enchants which don't have listed duration
5571 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5572 if(!pEnchant)
5573 return;
5575 // Always go to temp enchantment slot
5576 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5578 // Enchantment will not be applied if a different one already exists
5579 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5580 return;
5582 // Apply the temporary enchantment
5583 item->SetEnchantment(slot, enchant_id, duration*IN_MILISECONDS, 0);
5584 item_owner->ApplyEnchantment(item,slot,true);
5588 void Spell::EffectDisEnchant(uint32 /*i*/)
5590 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5591 return;
5593 Player* p_caster = (Player*)m_caster;
5594 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5595 return;
5597 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5599 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5601 // item will be removed at disenchanting end
5604 void Spell::EffectInebriate(uint32 /*i*/)
5606 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5607 return;
5609 Player *player = (Player*)unitTarget;
5610 uint16 currentDrunk = player->GetDrunkValue();
5611 uint16 drunkMod = damage * 256;
5612 if (currentDrunk + drunkMod > 0xFFFF)
5613 currentDrunk = 0xFFFF;
5614 else
5615 currentDrunk += drunkMod;
5616 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5619 void Spell::EffectFeedPet(uint32 i)
5621 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5622 return;
5624 Player *_player = (Player*)m_caster;
5626 Item* foodItem = m_targets.getItemTarget();
5627 if(!foodItem)
5628 return;
5630 Pet *pet = _player->GetPet();
5631 if(!pet)
5632 return;
5634 if(!pet->isAlive())
5635 return;
5637 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5638 if(benefit <= 0)
5639 return;
5641 uint32 count = 1;
5642 _player->DestroyItemCount(foodItem,count,true);
5643 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5645 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5648 void Spell::EffectDismissPet(uint32 /*i*/)
5650 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5651 return;
5653 Pet* pet = m_caster->GetPet();
5655 // not let dismiss dead pet
5656 if(!pet||!pet->isAlive())
5657 return;
5659 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5662 void Spell::EffectSummonObject(uint32 i)
5664 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5666 uint8 slot = 0;
5667 switch(m_spellInfo->Effect[i])
5669 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5670 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5671 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5672 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5673 default: return;
5676 uint64 guid = m_caster->m_ObjectSlot[slot];
5677 if(guid != 0)
5679 GameObject* obj = NULL;
5680 if( m_caster )
5681 obj = m_caster->GetMap()->GetGameObject(guid);
5683 if(obj) obj->Delete();
5684 m_caster->m_ObjectSlot[slot] = 0;
5687 GameObject* pGameObj = new GameObject;
5689 float x,y,z;
5690 // If dest location if present
5691 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5693 x = m_targets.m_destX;
5694 y = m_targets.m_destY;
5695 z = m_targets.m_destZ;
5697 // Summon in random point all other units if location present
5698 else
5699 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5701 Map *map = m_caster->GetMap();
5702 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
5703 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
5705 delete pGameObj;
5706 return;
5709 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5710 int32 duration = GetSpellDuration(m_spellInfo);
5711 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5712 pGameObj->SetSpellId(m_spellInfo->Id);
5713 m_caster->AddGameObject(pGameObj);
5715 map->Add(pGameObj);
5716 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5717 data << pGameObj->GetGUID();
5718 m_caster->SendMessageToSet(&data,true);
5720 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5723 void Spell::EffectResurrect(uint32 /*effIndex*/)
5725 if(!unitTarget)
5726 return;
5727 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5728 return;
5730 if(unitTarget->isAlive())
5731 return;
5732 if(!unitTarget->IsInWorld())
5733 return;
5735 switch (m_spellInfo->Id)
5737 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5738 case 8342:
5739 if (roll_chance_i(67))
5741 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5742 return;
5744 break;
5745 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5746 case 22999:
5747 if (roll_chance_i(50))
5749 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5750 return;
5752 break;
5753 default:
5754 break;
5757 Player* pTarget = ((Player*)unitTarget);
5759 if(pTarget->isRessurectRequested()) // already have one active request
5760 return;
5762 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5763 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5765 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5766 SendResurrectRequest(pTarget);
5769 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5771 if(!unitTarget || !unitTarget->isAlive())
5772 return;
5774 if( unitTarget->m_extraAttacks )
5775 return;
5777 unitTarget->m_extraAttacks = damage;
5780 void Spell::EffectParry(uint32 /*i*/)
5782 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5783 ((Player*)unitTarget)->SetCanParry(true);
5786 void Spell::EffectBlock(uint32 /*i*/)
5788 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5789 ((Player*)unitTarget)->SetCanBlock(true);
5792 void Spell::EffectMomentMove(uint32 i)
5794 if(unitTarget->isInFlight())
5795 return;
5797 if( m_spellInfo->rangeIndex== 1) //self range
5799 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5801 // before caster
5802 float fx,fy,fz;
5803 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5804 float ox,oy,oz;
5805 unitTarget->GetPosition(ox,oy,oz);
5807 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5808 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5810 fx = fx2;
5811 fy = fy2;
5812 fz = fz2;
5813 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5816 unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(),unitTarget==m_caster);
5820 void Spell::EffectReputation(uint32 i)
5822 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5823 return;
5825 Player *_player = (Player*)unitTarget;
5827 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5829 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5831 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5833 if(!factionEntry)
5834 return;
5836 _player->GetReputationMgr().ModifyReputation(factionEntry,rep_change);
5839 void Spell::EffectQuestComplete(uint32 i)
5841 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5842 return;
5844 Player *_player = (Player*)m_caster;
5846 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5847 _player->AreaExploredOrEventHappens(quest_id);
5850 void Spell::EffectSelfResurrect(uint32 i)
5852 if(!unitTarget || unitTarget->isAlive())
5853 return;
5854 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5855 return;
5856 if(!unitTarget->IsInWorld())
5857 return;
5859 uint32 health = 0;
5860 uint32 mana = 0;
5862 // flat case
5863 if(damage < 0)
5865 health = uint32(-damage);
5866 mana = m_spellInfo->EffectMiscValue[i];
5868 // percent case
5869 else
5871 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5872 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5873 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5876 Player *plr = ((Player*)unitTarget);
5877 plr->ResurrectPlayer(0.0f);
5879 plr->SetHealth( health );
5880 plr->SetPower(POWER_MANA, mana );
5881 plr->SetPower(POWER_RAGE, 0 );
5882 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5884 plr->SpawnCorpseBones();
5886 plr->SaveToDB();
5889 void Spell::EffectSkinning(uint32 /*i*/)
5891 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5892 return;
5893 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5894 return;
5896 Creature* creature = (Creature*) unitTarget;
5897 int32 targetLevel = creature->getLevel();
5899 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5901 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5902 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5904 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5906 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5908 // Double chances for elites
5909 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5912 void Spell::EffectCharge(uint32 /*i*/)
5914 if(!unitTarget || !m_caster)
5915 return;
5917 float x, y, z;
5918 unitTarget->GetContactPoint(m_caster, x, y, z);
5919 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5920 ((Creature *)unitTarget)->StopMoving();
5922 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5923 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5925 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5926 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5928 // not all charge effects used in negative spells
5929 if ( !IsPositiveSpell(m_spellInfo->Id))
5930 m_caster->Attack(unitTarget,true);
5933 void Spell::EffectSummonCritter(uint32 i)
5935 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5936 return;
5937 Player* player = (Player*)m_caster;
5939 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5940 if(!pet_entry)
5941 return;
5943 Pet* old_critter = player->GetMiniPet();
5945 // for same pet just despawn
5946 if(old_critter && old_critter->GetEntry() == pet_entry)
5948 player->RemoveMiniPet();
5949 return;
5952 // despawn old pet before summon new
5953 if(old_critter)
5954 player->RemoveMiniPet();
5956 // summon new pet
5957 Pet* critter = new Pet(MINI_PET);
5959 Map *map = m_caster->GetMap();
5960 uint32 pet_number = objmgr.GeneratePetNumber();
5961 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
5962 pet_entry, pet_number))
5964 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5965 delete critter;
5966 return;
5969 float x,y,z;
5970 // If dest location if present
5971 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5973 x = m_targets.m_destX;
5974 y = m_targets.m_destY;
5975 z = m_targets.m_destZ;
5977 // Summon if dest location not present near caster
5978 else
5979 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5981 critter->Relocate(x,y,z,m_caster->GetOrientation());
5983 if(!critter->IsPositionValid())
5985 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5986 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5987 delete critter;
5988 return;
5991 critter->SetOwnerGUID(m_caster->GetGUID());
5992 critter->SetCreatorGUID(m_caster->GetGUID());
5993 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5994 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5996 critter->AIM_Initialize();
5997 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5998 critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
5999 critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag);
6000 // some mini-pets have quests
6002 // set timer for unsummon
6003 int32 duration = GetSpellDuration(m_spellInfo);
6004 if(duration > 0)
6005 critter->SetDuration(duration);
6007 std::string name = player->GetName();
6008 name.append(petTypeSuffix[critter->getPetType()]);
6009 critter->SetName( name );
6010 player->SetMiniPet(critter);
6012 map->Add((Creature*)critter);
6015 void Spell::EffectKnockBack(uint32 i)
6017 if(!unitTarget || !m_caster)
6018 return;
6020 // Effect only works on players
6021 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6022 return;
6024 float vsin = sin(m_caster->GetAngle(unitTarget));
6025 float vcos = cos(m_caster->GetAngle(unitTarget));
6027 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6028 data.append(unitTarget->GetPackGUID());
6029 data << uint32(0); // Sequence
6030 data << float(vcos); // x direction
6031 data << float(vsin); // y direction
6032 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
6033 data << float(damage/-10); // Z Movement speed (vertical)
6035 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6038 void Spell::EffectSendTaxi(uint32 i)
6040 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6041 return;
6043 ((Player*)unitTarget)->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id);
6046 void Spell::EffectPlayerPull(uint32 i)
6048 if(!unitTarget || !m_caster)
6049 return;
6051 // Effect only works on players
6052 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6053 return;
6055 float vsin = sin(unitTarget->GetAngle(m_caster));
6056 float vcos = cos(unitTarget->GetAngle(m_caster));
6058 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6059 data.append(unitTarget->GetPackGUID());
6060 data << uint32(0); // Sequence
6061 data << float(vcos); // x direction
6062 data << float(vsin); // y direction
6063 // Horizontal speed
6064 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
6065 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
6067 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6070 void Spell::EffectDispelMechanic(uint32 i)
6072 if(!unitTarget)
6073 return;
6075 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
6077 Unit::AuraMap& Auras = unitTarget->GetAuras();
6078 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
6080 next = iter;
6081 ++next;
6082 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
6083 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
6085 unitTarget->RemoveAurasDueToSpell(spell->Id);
6086 if(Auras.empty())
6087 break;
6088 else
6089 next = Auras.begin();
6092 return;
6095 void Spell::EffectSummonDeadPet(uint32 /*i*/)
6097 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6098 return;
6099 Player *_player = (Player*)m_caster;
6100 Pet *pet = _player->GetPet();
6101 if(!pet)
6102 return;
6103 if(pet->isAlive())
6104 return;
6105 if(damage < 0)
6106 return;
6107 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6108 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6109 pet->setDeathState( ALIVE );
6110 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6111 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6113 pet->AIM_Initialize();
6115 _player->PetSpellInitialize();
6116 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6119 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6121 int32 mana = 0;
6122 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6124 if(!m_caster->m_TotemSlot[slot])
6125 continue;
6127 Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_TotemSlot[slot]);
6128 if(totem && totem->isTotem())
6130 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6131 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6132 if(spellInfo)
6134 uint32 manacost = m_caster->GetCreateMana() * spellInfo->ManaCostPercentage / 100;
6135 mana += manacost * damage / 100;
6137 ((Totem*)totem)->UnSummon();
6141 if (mana)
6142 m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
6145 void Spell::EffectDurabilityDamage(uint32 i)
6147 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6148 return;
6150 int32 slot = m_spellInfo->EffectMiscValue[i];
6152 // FIXME: some spells effects have value -1/-2
6153 // Possibly its mean -1 all player equipped items and -2 all items
6154 if(slot < 0)
6156 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6157 return;
6160 // invalid slot value
6161 if(slot >= INVENTORY_SLOT_BAG_END)
6162 return;
6164 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6165 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6168 void Spell::EffectDurabilityDamagePCT(uint32 i)
6170 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6171 return;
6173 int32 slot = m_spellInfo->EffectMiscValue[i];
6175 // FIXME: some spells effects have value -1/-2
6176 // Possibly its mean -1 all player equipped items and -2 all items
6177 if(slot < 0)
6179 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6180 return;
6183 // invalid slot value
6184 if(slot >= INVENTORY_SLOT_BAG_END)
6185 return;
6187 if(damage <= 0)
6188 return;
6190 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6191 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6194 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6196 if(!unitTarget)
6197 return;
6199 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6202 void Spell::EffectTransmitted(uint32 effIndex)
6204 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6206 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6208 if (!goinfo)
6210 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6211 return;
6214 float fx,fy,fz;
6216 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6218 fx = m_targets.m_destX;
6219 fy = m_targets.m_destY;
6220 fz = m_targets.m_destZ;
6222 //FIXME: this can be better check for most objects but still hack
6223 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6225 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6226 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6228 else
6230 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6231 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6232 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6234 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6237 Map *cMap = m_caster->GetMap();
6239 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6241 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6242 { // but this is not proper, we really need to ignore not materialized objects
6243 SendCastResult(SPELL_FAILED_NOT_HERE);
6244 SendChannelUpdate(0);
6245 return;
6248 // replace by water level in this case
6249 fz = cMap->GetWaterLevel(fx,fy);
6251 // if gameobject is summoning object, it should be spawned right on caster's position
6252 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6254 m_caster->GetPosition(fx,fy,fz);
6257 GameObject* pGameObj = new GameObject;
6259 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6260 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
6262 delete pGameObj;
6263 return;
6266 int32 duration = GetSpellDuration(m_spellInfo);
6268 switch(goinfo->type)
6270 case GAMEOBJECT_TYPE_FISHINGNODE:
6272 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6273 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6275 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6276 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6277 int32 lastSec = 0;
6278 switch(urand(0, 3))
6280 case 0: lastSec = 3; break;
6281 case 1: lastSec = 7; break;
6282 case 2: lastSec = 13; break;
6283 case 3: lastSec = 17; break;
6286 duration = duration - lastSec*IN_MILISECONDS + FISHING_BOBBER_READY_TIME*IN_MILISECONDS;
6287 break;
6289 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6291 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6293 pGameObj->AddUniqueUse((Player*)m_caster);
6294 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6296 break;
6298 case GAMEOBJECT_TYPE_FISHINGHOLE:
6299 case GAMEOBJECT_TYPE_CHEST:
6300 default:
6302 break;
6306 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6308 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6310 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6311 pGameObj->SetSpellId(m_spellInfo->Id);
6313 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
6314 //m_caster->AddGameObject(pGameObj);
6315 //m_ObjToDel.push_back(pGameObj);
6317 cMap->Add(pGameObj);
6319 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6320 data << uint64(pGameObj->GetGUID());
6321 m_caster->SendMessageToSet(&data,true);
6323 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6325 GameObject* linkedGO = new GameObject;
6326 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6327 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
6329 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6330 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6331 linkedGO->SetSpellId(m_spellInfo->Id);
6332 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6334 linkedGO->GetMap()->Add(linkedGO);
6336 else
6338 delete linkedGO;
6339 linkedGO = NULL;
6340 return;
6345 void Spell::EffectProspecting(uint32 /*i*/)
6347 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6348 return;
6350 Player* p_caster = (Player*)m_caster;
6351 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6352 return;
6354 if(itemTarget->GetCount() < 5)
6355 return;
6357 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6359 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6360 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6361 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6364 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6367 void Spell::EffectMilling(uint32 /*i*/)
6369 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6370 return;
6372 Player* p_caster = (Player*)m_caster;
6373 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6374 return;
6376 if(itemTarget->GetCount() < 5)
6377 return;
6379 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6381 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6382 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6383 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6386 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6389 void Spell::EffectSkill(uint32 /*i*/)
6391 sLog.outDebug("WORLD: SkillEFFECT");
6394 void Spell::EffectSummonDemon(uint32 i)
6396 // select center of summon position
6397 float center_x = m_targets.m_destX;
6398 float center_y = m_targets.m_destY;
6399 float center_z = m_targets.m_destZ;
6401 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
6403 int32 amount = damage > 0 ? damage : 1;
6405 for(int32 count = 0; count < amount; ++count)
6407 float px, py, pz;
6408 // If dest location if present
6409 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6411 // Summon 1 unit in dest location
6412 if (count == 0)
6414 px = m_targets.m_destX;
6415 py = m_targets.m_destY;
6416 pz = m_targets.m_destZ;
6418 // Summon in random point all other units if location present
6419 else
6420 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
6422 // Summon if dest location not present near caster
6423 else
6424 m_caster->GetClosePoint(px,py,pz,3.0f);
6426 int32 duration = GetSpellDuration(m_spellInfo);
6428 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,duration);
6429 if (!Charmed) // something fatal, not attempt more
6430 return;
6432 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6433 Charmed->SetLevel(m_caster->getLevel());
6435 // TODO: Add damage/mana/hp according to level
6437 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6439 // Enslave demon effect, without mana cost and cooldown
6440 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6442 // Inferno effect
6443 Charmed->CastSpell(Charmed, 22703, true, 0);
6448 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6449 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6450 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6451 This is why we use a half sec delay between the visual effect and the resurrection itself */
6452 void Spell::EffectSpiritHeal(uint32 /*i*/)
6455 if(!unitTarget || unitTarget->isAlive())
6456 return;
6457 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6458 return;
6459 if(!unitTarget->IsInWorld())
6460 return;
6462 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6463 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6464 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6465 ((Player*)unitTarget)->SpawnCorpseBones();
6469 // remove insignia spell effect
6470 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6472 sLog.outDebug("Effect: SkinPlayerCorpse");
6473 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6474 return;
6476 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6479 void Spell::EffectStealBeneficialBuff(uint32 i)
6481 sLog.outDebug("Effect: StealBeneficialBuff");
6483 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6484 return;
6486 std::vector <Aura *> steal_list;
6487 // Create dispel mask by dispel type
6488 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6489 Unit::AuraMap const& auras = unitTarget->GetAuras();
6490 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6492 Aura *aur = (*itr).second;
6493 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6495 // Need check for passive? this
6496 if (aur->IsPositive() && !aur->IsPassive() && !(aur->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE))
6497 steal_list.push_back(aur);
6500 // Ok if exist some buffs for dispel try dispel it
6501 if (!steal_list.empty())
6503 std::list < std::pair<uint32,uint64> > success_list;
6504 int32 list_size = steal_list.size();
6505 // Dispell N = damage buffs (or while exist buffs for dispel)
6506 for (int32 count=0; count < damage && list_size > 0; ++count)
6508 // Random select buff for dispel
6509 Aura *aur = steal_list[urand(0, list_size-1)];
6510 // Not use chance for steal
6511 // TODO possible need do it
6512 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6514 // Remove buff from list for prevent doubles
6515 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6517 Aura *stealed = *j;
6518 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6520 j = steal_list.erase(j);
6521 --list_size;
6523 else
6524 ++j;
6527 // Really try steal and send log
6528 if (!success_list.empty())
6530 int32 count = success_list.size();
6531 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6532 data.append(unitTarget->GetPackGUID()); // Victim GUID
6533 data.append(m_caster->GetPackGUID()); // Caster GUID
6534 data << uint32(m_spellInfo->Id); // Dispell spell id
6535 data << uint8(0); // not used
6536 data << uint32(count); // count
6537 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6539 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6540 data << uint32(spellInfo->Id); // Spell Id
6541 data << uint8(0); // 0 - steals !=0 transfers
6542 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6544 m_caster->SendMessageToSet(&data, true);
6549 void Spell::EffectKillCredit(uint32 i)
6551 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6552 return;
6554 ((Player*)unitTarget)->RewardPlayerAndGroupAtEvent(m_spellInfo->EffectMiscValue[i], unitTarget);
6557 void Spell::EffectQuestFail(uint32 i)
6559 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6560 return;
6562 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6565 void Spell::EffectActivateRune(uint32 eff_idx)
6567 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6568 return;
6570 Player *plr = (Player*)m_caster;
6572 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6573 return;
6575 for(uint32 j = 0; j < MAX_RUNES; ++j)
6577 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6579 plr->SetRuneCooldown(j, 0);
6584 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6586 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6587 ((Player*)unitTarget)->SetCanTitanGrip(true);
6590 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6592 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6593 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6594 return;
6596 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);