[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / SpellEffects.cpp
blob9f9505da053b8bd8a07383f0e57a8ec658f0ef65
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGroundMgr.h"
49 #include "BattleGround.h"
50 #include "BattleGroundEY.h"
51 #include "BattleGroundWS.h"
52 #include "VMapFactory.h"
53 #include "Language.h"
54 #include "SocialMgr.h"
55 #include "Util.h"
56 #include "TemporarySummon.h"
57 #include "ScriptCalls.h"
58 #include "SkillDiscovery.h"
60 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
62 &Spell::EffectNULL, // 0
63 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
64 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
65 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
66 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
67 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
68 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
69 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
70 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
71 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
72 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
73 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
74 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
75 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
76 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
77 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
78 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
79 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
80 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
81 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
82 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
83 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
84 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
85 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
86 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
87 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
88 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
89 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
90 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
91 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
92 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
93 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
94 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
95 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
96 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
97 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
98 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
99 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
100 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
101 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
102 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
103 &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP
104 &Spell::EffectUnused, // 42 SPELL_EFFECT_JUMP2
105 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
106 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
107 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
108 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
109 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
110 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
111 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
112 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
113 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
114 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
115 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
116 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
117 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
118 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
119 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
120 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
121 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
122 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
123 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
124 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
125 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
126 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
127 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
128 &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
129 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
130 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
131 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
132 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
133 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
134 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
135 &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
136 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
137 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
138 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
139 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
140 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
141 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
142 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
143 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
144 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
145 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
146 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
147 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
148 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
149 &Spell::EffectUnused, // 87 SPELL_EFFECT_WMO_DAMAGE
150 &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
151 &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
152 &Spell::EffectUnused, // 90 SPELL_EFFECT_KILL_CREDIT
153 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
154 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
155 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
156 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
157 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
158 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
159 &Spell::EffectUnused, // 97 SPELL_EFFECT_97
160 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
161 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
162 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
163 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
164 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
165 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
166 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
167 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
168 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
169 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
170 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
171 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
172 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
173 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
174 &Spell::EffectUnused, //112 SPELL_EFFECT_112
175 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
176 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
177 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
178 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
179 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
180 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
181 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
182 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
183 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
184 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
185 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
186 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
187 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
188 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
189 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
190 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
191 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
192 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
193 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
194 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
195 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
196 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
197 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
198 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
199 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
200 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
201 &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
202 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
203 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
204 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
205 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
206 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
207 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
208 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
209 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
210 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
211 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
212 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
213 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
214 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
215 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
216 &Spell::EffectNULL, //154 unused
217 &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.
218 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
219 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
220 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
221 &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
224 void Spell::EffectNULL(uint32 /*i*/)
226 sLog.outDebug("WORLD: Spell Effect DUMMY");
229 void Spell::EffectUnused(uint32 /*i*/)
231 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
234 void Spell::EffectResurrectNew(uint32 i)
236 if(!unitTarget || unitTarget->isAlive())
237 return;
239 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
240 return;
242 if(!unitTarget->IsInWorld())
243 return;
245 Player* pTarget = ((Player*)unitTarget);
247 if(pTarget->isRessurectRequested()) // already have one active request
248 return;
250 uint32 health = damage;
251 uint32 mana = m_spellInfo->EffectMiscValue[i];
252 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
253 SendResurrectRequest(pTarget);
256 void Spell::EffectInstaKill(uint32 /*i*/)
258 if( !unitTarget || !unitTarget->isAlive() )
259 return;
261 // Demonic Sacrifice
262 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
264 uint32 entry = unitTarget->GetEntry();
265 uint32 spellID;
266 switch(entry)
268 case 416: spellID=18789; break; //imp
269 case 417: spellID=18792; break; //fellhunter
270 case 1860: spellID=18790; break; //void
271 case 1863: spellID=18791; break; //succubus
272 case 17252: spellID=35701; break; //fellguard
273 default:
274 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
275 return;
278 m_caster->CastSpell(m_caster,spellID,true);
281 if(m_caster==unitTarget) // prevent interrupt message
282 finish();
284 uint32 health = unitTarget->GetHealth();
285 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
288 void Spell::EffectEnvirinmentalDMG(uint32 i)
290 uint32 absorb = 0;
291 uint32 resist = 0;
293 // Note: this hack with damage replace required until GO casting not implemented
294 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
295 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
296 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
298 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
300 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
301 if(m_caster->GetTypeId() == TYPEID_PLAYER)
302 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
305 void Spell::EffectSchoolDMG(uint32 effect_idx)
307 if( unitTarget && unitTarget->isAlive())
309 switch(m_spellInfo->SpellFamilyName)
311 case SPELLFAMILY_GENERIC:
313 //Gore
314 if(m_spellInfo->SpellIconID == 2269 )
316 damage+= rand()%2 ? damage : 0;
319 switch(m_spellInfo->Id) // better way to check unknown
321 // Meteor like spells (divided damage to targets)
322 case 24340: case 26558: case 28884: // Meteor
323 case 36837: case 38903: case 41276: // Meteor
324 case 26789: // Shard of the Fallen Star
325 case 31436: // Malevolent Cleave
326 case 35181: // Dive Bomb
327 case 40810: case 43267: case 43268: // Saber Lash
328 case 42384: // Brutal Swipe
329 case 45150: // Meteor Slash
331 uint32 count = 0;
332 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
333 if(ihit->effectMask & (1<<effect_idx))
334 ++count;
336 damage /= count; // divide to all targets
337 break;
339 // percent from health with min
340 case 25599: // Thundercrash
342 damage = unitTarget->GetHealth() / 2;
343 if(damage < 200)
344 damage = 200;
345 break;
347 // Intercept (warrior spell trigger)
348 case 20253:
349 case 61491:
351 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
352 break;
355 break;
358 case SPELLFAMILY_MAGE:
360 // Arcane Blast
361 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
363 m_caster->CastSpell(m_caster,36032,true);
365 break;
367 case SPELLFAMILY_WARRIOR:
369 // Bloodthirst
370 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
372 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
374 // Shield Slam
375 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
376 damage += int32(m_caster->GetShieldBlockValue());
377 // Victory Rush
378 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
380 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
381 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
383 // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
384 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000400LL)
385 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
386 // Heroic Throw ${$m1+$AP*.50}
387 else if(m_spellInfo->SpellFamilyFlags & 0x0000000100000000LL)
388 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
389 // Shockwave ${$m3/100*$AP}
390 else if(m_spellInfo->SpellFamilyFlags & 0x0000800000000000LL)
392 int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
393 if (pct > 0)
394 damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
395 break;
397 break;
399 case SPELLFAMILY_WARLOCK:
401 // Incinerate Rank 1 & 2
402 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
404 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
405 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
406 damage += int32(damage*0.25f);
408 break;
410 case SPELLFAMILY_PRIEST:
412 // Shadow Word: Death - deals damage equal to damage done to caster
413 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
414 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
415 break;
417 case SPELLFAMILY_DRUID:
419 // Ferocious Bite
420 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
422 // converts each extra point of energy into ($f1+$AP/410) additional damage
423 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
424 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
425 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
426 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
427 m_caster->SetPower(POWER_ENERGY,0);
429 // Rake
430 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
432 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
434 // Swipe
435 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
437 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
439 //Mangle Bonus for the initial damage of Lacerate and Rake
440 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
441 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
443 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
444 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
445 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
447 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
448 break;
451 break;
453 case SPELLFAMILY_ROGUE:
455 // Envenom
456 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
458 // consume from stack dozes not more that have combo-points
459 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
461 Aura *poison = 0;
462 // Lookup for Deadly poison (only attacker applied)
463 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
464 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
465 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
466 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
467 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
469 poison = *itr;
470 break;
472 // count consumed deadly poison doses at target
473 if (poison)
475 uint32 spellId = poison->GetId();
476 uint32 doses = poison->GetStackAmount();
477 if (doses > combo)
478 doses = combo;
479 for (int i=0; i< doses; i++)
480 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
481 damage *= doses;
482 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
484 // Eviscerate and Envenom Bonus Damage (item set effect)
485 if(m_caster->GetDummyAura(37169))
486 damage += ((Player*)m_caster)->GetComboPoints()*40;
489 // Eviscerate
490 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
492 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
494 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
495 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
497 // Eviscerate and Envenom Bonus Damage (item set effect)
498 if(m_caster->GetDummyAura(37169))
499 damage += combo*40;
502 // Gouge
503 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
505 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.02f);
507 // Instant Poison
508 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
510 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
512 // Wound Poison
513 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
515 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
517 break;
519 case SPELLFAMILY_HUNTER:
521 // Mongoose Bite
522 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
524 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
526 // Counterattack
527 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
529 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
531 // Arcane Shot
532 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
534 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
536 // Steady Shot
537 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
539 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
540 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
542 // Explosive Trap Effect
543 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
545 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
547 break;
549 case SPELLFAMILY_PALADIN:
551 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
552 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
554 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
555 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
556 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
557 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
558 // Get stack of Holy Vengeance on the target added by caster
559 uint32 stacks = 0;
560 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
561 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
562 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
564 stacks = (*itr)->GetStackAmount();
565 break;
567 // + 10% for each application of Holy Vengeance on the target
568 if(stacks)
569 damage += damage * stacks * 10 /100;
571 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
572 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
574 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
575 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
576 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
577 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
579 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
580 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
582 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
583 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
584 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
585 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
587 // Hammer of the Righteous
588 else if(m_spellInfo->SpellFamilyFlags&0x0004000000000000LL)
590 // Add main hand dps * effect[2] amount
591 float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
592 int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
593 damage += count * int32(averange * 1000) / m_caster->GetAttackTime(BASE_ATTACK);
595 break;
599 if(damage >= 0)
600 m_damage+= damage;
604 void Spell::EffectDummy(uint32 i)
606 if(!unitTarget && !gameObjTarget && !itemTarget)
607 return;
609 // selection by spell family
610 switch(m_spellInfo->SpellFamilyName)
612 case SPELLFAMILY_GENERIC:
614 switch(m_spellInfo->Id )
616 case 8063: // Deviate Fish
618 if(m_caster->GetTypeId() != TYPEID_PLAYER)
619 return;
621 uint32 spell_id = 0;
622 switch(urand(1,5))
624 case 1: spell_id = 8064; break; // Sleepy
625 case 2: spell_id = 8065; break; // Invigorate
626 case 3: spell_id = 8066; break; // Shrink
627 case 4: spell_id = 8067; break; // Party Time!
628 case 5: spell_id = 8068; break; // Healthy Spirit
630 m_caster->CastSpell(m_caster,spell_id,true,NULL);
631 return;
633 case 8213: // Savory Deviate Delight
635 if(m_caster->GetTypeId() != TYPEID_PLAYER)
636 return;
638 uint32 spell_id = 0;
639 switch(urand(1,2))
641 // Flip Out - ninja
642 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
643 // Yaaarrrr - pirate
644 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
646 m_caster->CastSpell(m_caster,spell_id,true,NULL);
647 return;
649 case 8593: // Symbol of life (restore creature to life)
650 case 31225: // Shimmering Vessel (restore creature to life)
652 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
653 return;
654 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
655 return;
657 case 12162: // Deep wounds
658 case 12850: // (now good common check for this spells)
659 case 12868:
661 if(!unitTarget)
662 return;
664 float damage;
665 // DW should benefit of attack power, damage percent mods etc.
666 // TODO: check if using offhand damage is correct and if it should be divided by 2
667 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
668 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
669 else
670 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
672 switch (m_spellInfo->Id)
674 case 12850: damage *= 0.2f; break;
675 case 12162: damage *= 0.4f; break;
676 case 12868: damage *= 0.6f; break;
677 default:
678 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
679 return;
682 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
683 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
684 return;
686 case 13120: // net-o-matic
688 if(!unitTarget)
689 return;
691 uint32 spell_id = 0;
693 uint32 roll = urand(0, 99);
695 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
696 spell_id = 16566;
697 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
698 spell_id = 13119;
699 else // normal root
700 spell_id = 13099;
702 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
703 return;
705 case 13567: // Dummy Trigger
707 // can be used for different aura triggering, so select by aura
708 if(!m_triggeredByAuraSpell || !unitTarget)
709 return;
711 switch(m_triggeredByAuraSpell->Id)
713 case 26467: // Persistent Shield
714 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
715 break;
716 default:
717 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
718 break;
720 return;
722 case 15998: // Capture Worg Pup
723 case 29435: // Capture Female Kaliri Hatchling
725 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
726 return;
728 Creature* creatureTarget = (Creature*)unitTarget;
729 creatureTarget->setDeathState(JUST_DIED);
730 creatureTarget->RemoveCorpse();
731 creatureTarget->SetHealth(0); // just for nice GM-mode view
732 return;
734 case 16589: // Noggenfogger Elixir
736 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
737 return;
739 uint32 spell_id = 0;
740 switch(urand(1,3))
742 case 1: spell_id = 16595; break;
743 case 2: spell_id = 16593; break;
744 default:spell_id = 16591; break;
747 m_caster->CastSpell(m_caster,spell_id,true,NULL);
748 return;
750 case 17251: // Spirit Healer Res
752 if(!unitTarget || !m_originalCaster)
753 return;
755 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
757 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
758 data << unitTarget->GetGUID();
759 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
761 return;
763 case 17271: // Test Fetid Skull
765 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
766 return;
768 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
770 m_caster->CastSpell(m_caster,spell_id,true,NULL);
771 return;
773 case 20577: // Cannibalize
774 if (unitTarget)
775 m_caster->CastSpell(m_caster,20578,false,NULL);
776 return;
777 case 23019: // Crystal Prison Dummy DND
779 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
780 return;
782 Creature* creatureTarget = (Creature*)unitTarget;
783 if(creatureTarget->isPet())
784 return;
786 GameObject* pGameObj = new GameObject;
788 Map *map = creatureTarget->GetMap();
790 // create before death for get proper coordinates
791 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
792 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
793 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
795 delete pGameObj;
796 return;
799 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
800 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
801 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
802 pGameObj->SetSpellId(m_spellInfo->Id);
804 creatureTarget->setDeathState(JUST_DIED);
805 creatureTarget->RemoveCorpse();
806 creatureTarget->SetHealth(0); // just for nice GM-mode view
808 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
809 map->Add(pGameObj);
811 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
812 data << uint64(pGameObj->GetGUID());
813 m_caster->SendMessageToSet(&data,true);
815 return;
817 case 23074: // Arcanite Dragonling
818 if (!m_CastItem) return;
819 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
820 return;
821 case 23075: // Mithril Mechanical Dragonling
822 if (!m_CastItem) return;
823 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
824 return;
825 case 23076: // Mechanical Dragonling
826 if (!m_CastItem) return;
827 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
828 return;
829 case 23133: // Gnomish Battle Chicken
830 if (!m_CastItem) return;
831 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
832 return;
833 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
835 int32 r = irand(0, 119);
836 if ( r < 20 ) // 1/6 polymorph
837 m_caster->CastSpell(m_caster,23444,true);
838 else if ( r < 100 ) // 4/6 evil twin
839 m_caster->CastSpell(m_caster,23445,true);
840 else // 1/6 miss the target
841 m_caster->CastSpell(m_caster,36902,true);
842 return;
844 case 23453: // Ultrasafe Transporter: Gadgetzan
845 if ( roll_chance_i(50) ) // success
846 m_caster->CastSpell(m_caster,23441,true);
847 else // failure
848 m_caster->CastSpell(m_caster,23446,true);
849 return;
850 case 23645: // Hourglass Sand
851 m_caster->RemoveAurasDueToSpell(23170);
852 return;
853 case 23725: // Gift of Life (warrior bwl trinket)
854 m_caster->CastSpell(m_caster,23782,true);
855 m_caster->CastSpell(m_caster,23783,true);
856 return;
857 case 25860: // Reindeer Transformation
859 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
860 return;
862 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
863 float speed = m_caster->GetSpeedRate(MOVE_RUN);
865 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
867 //5 different spells used depending on mounted speed and if mount can fly or not
868 if (flyspeed >= 4.1f)
869 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
870 else if (flyspeed >= 3.8f)
871 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
872 else if (flyspeed >= 1.6f)
873 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
874 else if (speed >= 2.0f)
875 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
876 else
877 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
879 return;
881 //case 26074: // Holiday Cheer
882 // return; -- implemented at client side
883 case 28006: // Arcane Cloaking
885 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
886 m_caster->CastSpell(unitTarget,29294,true);
887 return;
889 case 28730: // Arcane Torrent (Mana)
891 Aura * dummy = m_caster->GetDummyAura(28734);
892 if (dummy)
894 int32 bp = damage * dummy->GetStackAmount();
895 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
896 m_caster->RemoveAurasDueToSpell(28734);
898 return;
900 case 29200: // Purify Helboar Meat
902 if( m_caster->GetTypeId() != TYPEID_PLAYER )
903 return;
905 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
907 m_caster->CastSpell(m_caster,spell_id,true,NULL);
908 return;
910 case 29858: // Soulshatter
911 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
912 m_caster->CastSpell(unitTarget,32835,true);
913 return;
914 case 30458: // Nigh Invulnerability
915 if (!m_CastItem) return;
916 if(roll_chance_i(86)) // success
917 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
918 else // backfire in 14% casts
919 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
920 return;
921 case 30507: // Poultryizer
922 if (!m_CastItem) return;
923 if(roll_chance_i(80)) // success
924 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
925 else // backfire 20%
926 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
927 return;
928 case 33060: // Make a Wish
930 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
931 return;
933 uint32 spell_id = 0;
935 switch(urand(1,5))
937 case 1: spell_id = 33053; break;
938 case 2: spell_id = 33057; break;
939 case 3: spell_id = 33059; break;
940 case 4: spell_id = 33062; break;
941 case 5: spell_id = 33064; break;
944 m_caster->CastSpell(m_caster,spell_id,true,NULL);
945 return;
947 case 35745:
949 uint32 spell_id;
950 switch(m_caster->GetAreaId())
952 case 3900: spell_id = 35743; break;
953 case 3742: spell_id = 35744; break;
954 default: return;
957 m_caster->CastSpell(m_caster,spell_id,true);
958 return;
960 case 37674: // Chaos Blast
962 if(!unitTarget)
963 return;
965 int32 basepoints0 = 100;
966 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
967 return;
969 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
971 // selecting one from Bloodstained Fortune item
972 uint32 newitemid;
973 switch(urand(1,20))
975 case 1: newitemid = 32688; break;
976 case 2: newitemid = 32689; break;
977 case 3: newitemid = 32690; break;
978 case 4: newitemid = 32691; break;
979 case 5: newitemid = 32692; break;
980 case 6: newitemid = 32693; break;
981 case 7: newitemid = 32700; break;
982 case 8: newitemid = 32701; break;
983 case 9: newitemid = 32702; break;
984 case 10: newitemid = 32703; break;
985 case 11: newitemid = 32704; break;
986 case 12: newitemid = 32705; break;
987 case 13: newitemid = 32706; break;
988 case 14: newitemid = 32707; break;
989 case 15: newitemid = 32708; break;
990 case 16: newitemid = 32709; break;
991 case 17: newitemid = 32710; break;
992 case 18: newitemid = 32711; break;
993 case 19: newitemid = 32712; break;
994 case 20: newitemid = 32713; break;
995 default:
996 return;
999 DoCreateItem(i,newitemid);
1000 return;
1002 // Demon Broiled Surprise
1003 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1004 case 43723:
1006 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1007 return;
1009 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1010 return;
1013 case 44875: // Complete Raptor Capture
1015 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1016 return;
1018 Creature* creatureTarget = (Creature*)unitTarget;
1020 creatureTarget->setDeathState(JUST_DIED);
1021 creatureTarget->RemoveCorpse();
1022 creatureTarget->SetHealth(0); // just for nice GM-mode view
1024 //cast spell Raptor Capture Credit
1025 m_caster->CastSpell(m_caster,42337,true,NULL);
1026 return;
1028 case 34665: //Administer Antidote
1030 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1031 return;
1033 if(!unitTarget)
1034 return;
1036 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1037 if(!tempSummon)
1038 return;
1040 uint32 health = tempSummon->GetHealth();
1042 float x = tempSummon->GetPositionX();
1043 float y = tempSummon->GetPositionY();
1044 float z = tempSummon->GetPositionZ();
1045 float o = tempSummon->GetOrientation();
1046 tempSummon->UnSummon();
1048 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1049 if (!pCreature)
1050 return;
1052 pCreature->SetHealth(health);
1053 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1055 if (pCreature->AI())
1056 pCreature->AI()->AttackStart(m_caster);
1058 return;
1060 case 44997: // Converting Sentry
1062 //Converted Sentry Credit
1063 m_caster->CastSpell(m_caster, 45009, true);
1064 return;
1066 case 45030: // Impale Emissary
1068 // Emissary of Hate Credit
1069 m_caster->CastSpell(m_caster, 45088, true);
1070 return;
1072 case 50243: // Teach Language
1074 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1075 return;
1077 // spell has a 1/3 chance to trigger one of the below
1078 if(roll_chance_i(66))
1079 return;
1080 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1082 // 1000001 - gnomish binary
1083 m_caster->CastSpell(m_caster, 50242, true);
1085 else
1087 // 01001000 - goblin binary
1088 m_caster->CastSpell(m_caster, 50246, true);
1091 return;
1093 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1095 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1096 return;
1098 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1099 bg->EventPlayerDroppedFlag((Player*)m_caster);
1101 m_caster->CastSpell(m_caster, 30452, true, NULL);
1102 return;
1104 case 53341:
1105 case 53343:
1107 m_caster->CastSpell(m_caster,54586,true);
1108 return;
1112 //All IconID Check in there
1113 switch(m_spellInfo->SpellIconID)
1115 // Berserking (troll racial traits)
1116 case 1661:
1118 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1119 int32 melee_mod = 10;
1120 if (healthPerc <= 40)
1121 melee_mod = 30;
1122 if (healthPerc < 100 && healthPerc > 40)
1123 melee_mod = 10+(100-healthPerc)/3;
1125 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1126 int32 hasteModBasePoints1 = (5-melee_mod);
1127 int32 hasteModBasePoints2 = 5;
1129 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1130 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1131 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1132 return;
1135 break;
1137 case SPELLFAMILY_MAGE:
1138 switch(m_spellInfo->Id )
1140 case 11958: // Cold Snap
1142 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1143 return;
1145 // immediately finishes the cooldown on Frost spells
1146 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1147 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1149 if (itr->second->state == PLAYERSPELL_REMOVED)
1150 continue;
1152 uint32 classspell = itr->first;
1153 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1155 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1156 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1157 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1159 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1161 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1162 data << uint32(classspell);
1163 data << uint64(m_caster->GetGUID());
1164 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1167 return;
1169 case 32826:
1171 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1173 //Polymorph Cast Visual Rank 1
1174 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1175 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1177 return;
1180 break;
1181 case SPELLFAMILY_WARRIOR:
1182 // Charge
1183 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1185 int32 chargeBasePoints0 = damage;
1186 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1187 return;
1189 // Execute
1190 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1192 if(!unitTarget)
1193 return;
1195 uint32 rage = m_caster->GetPower(POWER_RAGE);
1196 // Glyph of Execution bonus
1197 if (Aura *aura = m_caster->GetDummyAura(58367))
1198 rage+=aura->GetModifier()->m_amount;
1200 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1201 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1202 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1203 m_caster->SetPower(POWER_RAGE,0);
1204 return;
1206 // Slam
1207 if(m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL)
1209 if(!unitTarget)
1210 return;
1211 m_damage+=m_caster->CalculateDamage(m_attackType, false);
1212 m_damage+=damage;
1213 return;
1215 switch(m_spellInfo->Id)
1217 // Warrior's Wrath
1218 case 21977:
1220 if(!unitTarget)
1221 return;
1222 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1223 return;
1225 // Last Stand
1226 case 12975:
1228 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1229 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1230 return;
1232 // Bloodthirst
1233 case 23881:
1235 m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
1236 return;
1239 break;
1240 case SPELLFAMILY_WARLOCK:
1241 // Life Tap
1242 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1244 // In 303 exist spirit depend
1245 uint32 spirit = m_caster->GetStat(STAT_SPIRIT);
1246 switch (m_spellInfo->Id)
1248 case 1454: damage+=spirit; break;
1249 case 1455: damage+=spirit*15/10; break;
1250 case 1456: damage+=spirit*2; break;
1251 case 11687: damage+=spirit*25/10; break;
1252 case 11688:
1253 case 11689:
1254 case 27222:
1255 case 57946: damage+=spirit*3; break;
1256 default:
1257 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1258 return;
1260 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1261 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1262 if(int32(unitTarget->GetHealth()) > damage)
1264 // Shouldn't Appear in Combat Log
1265 unitTarget->ModifyHealth(-damage);
1267 int32 mana = damage;
1268 // Improved Life Tap mod
1269 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1270 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1272 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1273 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1275 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1277 // Mana Feed
1278 int32 manaFeedVal = 0;
1279 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1280 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1282 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1283 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1285 if(manaFeedVal > 0)
1287 manaFeedVal = manaFeedVal * mana / 100;
1288 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1291 else
1292 SendCastResult(SPELL_FAILED_FIZZLE);
1293 return;
1295 break;
1296 case SPELLFAMILY_PRIEST:
1297 // Penance
1298 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1300 if (!unitTarget)
1301 return;
1303 int hurt = 0;
1304 int heal = 0;
1305 switch(m_spellInfo->Id)
1307 case 47540: hurt = 47758; heal = 47757; break;
1308 case 53005: hurt = 53001; heal = 52986; break;
1309 case 53006: hurt = 53002; heal = 52987; break;
1310 case 53007: hurt = 53003; heal = 52988; break;
1311 default:
1312 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1313 return;
1315 if (m_caster->IsFriendlyTo(unitTarget))
1316 m_caster->CastSpell(unitTarget, heal, true, 0);
1317 else
1318 m_caster->CastSpell(unitTarget, hurt, true, 0);
1319 return;
1321 switch(m_spellInfo->Id )
1323 case 28598: // Touch of Weakness triggered spell
1325 if(!unitTarget || !m_triggeredByAuraSpell)
1326 return;
1328 uint32 spellid = 0;
1329 switch(m_triggeredByAuraSpell->Id)
1331 case 2652: spellid = 2943; break; // Rank 1
1332 case 19261: spellid = 19249; break; // Rank 2
1333 case 19262: spellid = 19251; break; // Rank 3
1334 case 19264: spellid = 19252; break; // Rank 4
1335 case 19265: spellid = 19253; break; // Rank 5
1336 case 19266: spellid = 19254; break; // Rank 6
1337 case 25461: spellid = 25460; break; // Rank 7
1338 default:
1339 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1340 return;
1342 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1343 return;
1346 break;
1347 case SPELLFAMILY_DRUID:
1348 break;
1349 case SPELLFAMILY_ROGUE:
1350 switch(m_spellInfo->Id )
1352 case 5938: // Shiv
1354 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1355 return;
1357 Player *pCaster = ((Player*)m_caster);
1359 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1360 if(!item)
1361 return;
1363 // all poison enchantments is temporary
1364 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1365 if(!enchant_id)
1366 return;
1368 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1369 if(!pEnchant)
1370 return;
1372 for (int s=0;s<3;s++)
1374 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1375 continue;
1377 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1378 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1379 continue;
1381 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1384 m_caster->CastSpell(unitTarget, 5940, true);
1385 return;
1387 case 14185: // Preparation Rogue
1389 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1390 return;
1392 //immediately finishes the cooldown on certain Rogue abilities
1393 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1394 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1396 uint32 classspell = itr->first;
1397 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1399 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1401 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1403 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1404 data << uint32(classspell);
1405 data << uint64(m_caster->GetGUID());
1406 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1409 return;
1411 case 31231: // Cheat Death
1413 m_caster->CastSpell(m_caster,45182,true);
1414 return;
1417 break;
1418 case SPELLFAMILY_HUNTER:
1419 // Steady Shot
1420 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1422 if( !unitTarget || !unitTarget->isAlive())
1423 return;
1425 bool found = false;
1427 // check dazed affect
1428 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1429 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1431 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1433 found = true;
1434 break;
1438 if(found)
1439 m_damage+= damage;
1440 return;
1443 switch(m_spellInfo->Id)
1445 case 23989: //Readiness talent
1447 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1448 return;
1450 //immediately finishes the cooldown for hunter abilities
1451 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1452 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1454 uint32 classspell = itr->first;
1455 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1457 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1459 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1461 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1462 data << uint32(classspell);
1463 data << uint64(m_caster->GetGUID());
1464 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1467 return;
1469 case 37506: // Scatter Shot
1471 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1472 return;
1474 // break Auto Shot and autohit
1475 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1476 m_caster->AttackStop();
1477 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1478 return;
1481 break;
1482 case SPELLFAMILY_PALADIN:
1483 switch(m_spellInfo->SpellIconID)
1485 case 156: // Holy Shock
1487 if(!unitTarget)
1488 return;
1490 int hurt = 0;
1491 int heal = 0;
1493 switch(m_spellInfo->Id)
1495 case 20473: hurt = 25912; heal = 25914; break;
1496 case 20929: hurt = 25911; heal = 25913; break;
1497 case 20930: hurt = 25902; heal = 25903; break;
1498 case 27174: hurt = 27176; heal = 27175; break;
1499 case 33072: hurt = 33073; heal = 33074; break;
1500 case 48824: hurt = 48822; heal = 48820; break;
1501 case 48825: hurt = 48823; heal = 48821; break;
1502 default:
1503 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1504 return;
1507 if(m_caster->IsFriendlyTo(unitTarget))
1508 m_caster->CastSpell(unitTarget, heal, true, 0);
1509 else
1510 m_caster->CastSpell(unitTarget, hurt, true, 0);
1512 return;
1514 case 561: // Judgement of command
1516 if(!unitTarget)
1517 return;
1519 uint32 spell_id = m_currentBasePoints[i]+1;
1520 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1521 if(!spell_proto)
1522 return;
1524 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1526 // decreased damage (/2) for non-stunned target.
1527 SpellModifier *mod = new SpellModifier;
1528 mod->op = SPELLMOD_DAMAGE;
1529 mod->value = -50;
1530 mod->type = SPELLMOD_PCT;
1531 mod->spellId = m_spellInfo->Id;
1532 mod->mask = 0x0000020000000000LL;
1533 mod->mask2= 0LL;
1535 ((Player*)m_caster)->AddSpellMod(mod, true);
1536 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1537 // mod deleted
1538 ((Player*)m_caster)->AddSpellMod(mod, false);
1540 else
1541 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1543 return;
1547 switch(m_spellInfo->Id)
1549 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1550 case 20187:
1552 if (!unitTarget)
1553 return;
1554 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1555 return;
1557 case 31789: // Righteous Defense (step 1)
1559 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1561 // non-standard cast requirement check
1562 if (!unitTarget || unitTarget->getAttackers().empty())
1564 // clear cooldown at fail
1565 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1567 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1569 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1570 data << uint32(m_spellInfo->Id);
1571 data << uint64(m_caster->GetGUID());
1572 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1575 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1576 return;
1579 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1580 // Clear targets for eff 1
1581 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1582 ihit->effectMask &= ~(1<<1);
1584 // not empty (checked)
1585 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1587 // chance to be selected from list
1588 float chance = 100.0f/attackers.size();
1589 uint32 count=0;
1590 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1592 if(!roll_chance_f(chance))
1593 continue;
1594 ++count;
1595 AddUnitTarget((*aItr), 1);
1598 // now let next effect cast spell at each target.
1599 return;
1601 case 37877: // Blessing of Faith
1603 if(!unitTarget)
1604 return;
1606 uint32 spell_id = 0;
1607 switch(unitTarget->getClass())
1609 case CLASS_DRUID: spell_id = 37878; break;
1610 case CLASS_PALADIN: spell_id = 37879; break;
1611 case CLASS_PRIEST: spell_id = 37880; break;
1612 case CLASS_SHAMAN: spell_id = 37881; break;
1613 default: return; // ignore for not healing classes
1616 m_caster->CastSpell(m_caster,spell_id,true);
1617 return;
1620 break;
1621 case SPELLFAMILY_SHAMAN:
1622 //Shaman Rockbiter Weapon
1623 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1625 // TODO: use expect spell for enchant (if exist talent)
1626 // In 3.0.3 no mods present for rockbiter
1627 uint32 spell_id = 0;
1628 switch(m_spellInfo->Id)
1630 case 8017: spell_id = 36494; break; // Rank 1
1631 case 8018: spell_id = 36750; break; // Rank 2
1632 case 8019: spell_id = 36755; break; // Rank 3
1633 case 10399: spell_id = 36759; break; // Rank 4
1634 default:
1635 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1636 return;
1639 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1641 if(!spellInfo)
1643 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1644 return;
1647 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1648 return;
1650 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1652 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1654 if(item->IsFitToSpellRequirements(m_spellInfo))
1656 Spell *spell = new Spell(m_caster, spellInfo, true);
1658 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1659 // at calculation applied affect from Elemental Weapons talent
1660 // real enchantment damage-1
1661 spell->m_currentBasePoints[1] = damage-1;
1663 SpellCastTargets targets;
1664 targets.setItemTarget( item );
1665 spell->prepare(&targets);
1669 return;
1671 // Healing Stream Totem
1672 if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
1674 m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1675 return;
1677 // Mana Spring Totem
1678 if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
1680 if(unitTarget->getPowerType()!=POWER_MANA)
1681 return;
1682 m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1683 return;
1685 if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
1687 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1688 return;
1689 // Glyph of Mana Tide
1690 Unit *owner = m_caster->GetOwner();
1691 if (owner)
1692 if (Aura *dummy = owner->GetDummyAura(55441))
1693 damage+=dummy->GetModifier()->m_amount;
1694 // Regenerate 6% of Total Mana Every 3 secs
1695 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1696 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1697 return;
1699 // Lava Lash
1700 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1702 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1703 return;
1704 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1705 if (item)
1707 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1708 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1709 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1711 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1712 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1713 (*itr)->GetCastItemGUID() == item->GetGUID())
1715 m_damage += m_damage * damage / 100;
1716 return;
1720 return;
1722 break;
1725 // pet auras
1726 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1728 m_caster->AddPetAura(petSpell);
1729 return;
1733 void Spell::EffectTriggerSpellWithValue(uint32 i)
1735 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1737 // normal case
1738 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1740 if(!spellInfo)
1742 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1743 return;
1746 int32 bp = damage;
1747 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1750 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1752 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1753 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1755 if(!spellInfo)
1757 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1758 return;
1761 finish();
1762 Spell *spell = new Spell(m_caster, spellInfo, true);
1764 SpellCastTargets targets;
1765 targets.setUnitTarget( unitTarget);
1766 spell->prepare(&targets);
1768 m_caster->SetCurrentCastedSpell(spell);
1769 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1773 void Spell::EffectForceCast(uint32 i)
1775 if( !unitTarget )
1776 return;
1778 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1780 // normal case
1781 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1783 if(!spellInfo)
1785 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1786 return;
1789 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1792 void Spell::EffectTriggerSpell(uint32 i)
1794 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1796 // special cases
1797 switch(triggered_spell_id)
1799 // Vanish
1800 case 18461:
1802 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1803 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1804 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1806 // if this spell is given to NPC it must handle rest by it's own AI
1807 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1808 return;
1810 // get highest rank of the Stealth spell
1811 uint32 spellId = 0;
1812 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1813 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1815 // only highest rank is shown in spell book, so simply check if shown in spell book
1816 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1817 continue;
1819 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1820 if (!spellInfo)
1821 continue;
1823 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1825 spellId = spellInfo->Id;
1826 break;
1830 // no Stealth spell found
1831 if (!spellId)
1832 return;
1834 // reset cooldown on it if needed
1835 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1836 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1838 m_caster->CastSpell(m_caster, spellId, true);
1839 return;
1841 // just skip
1842 case 23770: // Sayge's Dark Fortune of *
1843 // not exist, common cooldown can be implemented in scripts if need.
1844 return;
1845 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1846 case 29284:
1848 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1849 if (!spell)
1850 return;
1852 for (int i=0; i < spell->StackAmount; ++i)
1853 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1854 return;
1856 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1857 case 29286:
1859 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1860 if (!spell)
1861 return;
1863 for (int i=0; i < spell->StackAmount; ++i)
1864 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1865 return;
1867 // Righteous Defense
1868 case 31980:
1870 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1871 return;
1873 // Cloak of Shadows
1874 case 35729 :
1876 Unit::AuraMap& Auras = m_caster->GetAuras();
1877 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1879 // remove all harmful spells on you...
1880 if( // ignore positive and passive auras
1881 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1882 // ignore physical auras
1883 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1885 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1886 iter = Auras.begin();
1889 return;
1891 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1892 case 41967:
1894 if (Unit *pet = m_caster->GetPet())
1895 pet->CastSpell(pet, 28305, true);
1896 return;
1900 // normal case
1901 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1903 if(!spellInfo)
1905 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1906 return;
1909 // some triggered spells require specific equipment
1910 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1912 // main hand weapon required
1913 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1915 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1917 // skip spell if no weapon in slot or broken
1918 if(!item || item->IsBroken() )
1919 return;
1921 // skip spell if weapon not fit to triggered spell
1922 if(!item->IsFitToSpellRequirements(spellInfo))
1923 return;
1926 // offhand hand weapon required
1927 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1929 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1931 // skip spell if no weapon in slot or broken
1932 if(!item || item->IsBroken() )
1933 return;
1935 // skip spell if weapon not fit to triggered spell
1936 if(!item->IsFitToSpellRequirements(spellInfo))
1937 return;
1941 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1942 bool instant = false;
1943 for(uint32 j = i+1; j < 3; ++j)
1945 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1947 instant = true;
1948 break;
1952 if(instant)
1954 if (unitTarget)
1955 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1957 else
1958 m_TriggerSpells.push_back(spellInfo);
1961 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1963 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1965 // normal case
1966 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1968 if(!spellInfo)
1970 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1971 m_spellInfo->Id,effect_idx,triggered_spell_id);
1972 return;
1975 if (m_CastItem)
1976 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1978 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
1981 void Spell::EffectTeleportUnits(uint32 i)
1983 if(!unitTarget || unitTarget->isInFlight())
1984 return;
1986 switch (m_spellInfo->EffectImplicitTargetB[i])
1988 case TARGET_INNKEEPER_COORDINATES:
1990 // Only players can teleport to innkeeper
1991 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1992 return;
1994 ((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);
1995 return;
1997 case TARGET_TABLE_X_Y_Z_COORDINATES:
1999 // TODO: Only players can teleport?
2000 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2001 return;
2002 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2003 if(!st)
2005 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
2006 return;
2008 ((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);
2009 break;
2011 case TARGET_BEHIND_VICTIM:
2013 // Get selected target for player (or victim for units)
2014 Unit *pTarget = NULL;
2015 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2016 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2017 else
2018 pTarget = m_caster->getVictim();
2019 // No target present - return
2020 if (!pTarget)
2021 return;
2022 // Init dest coordinates
2023 uint32 mapid = m_caster->GetMapId();
2024 float x = m_targets.m_destX;
2025 float y = m_targets.m_destY;
2026 float z = m_targets.m_destZ;
2027 float orientation = pTarget->GetOrientation();
2028 // Teleport
2029 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2030 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
2031 else
2033 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2034 WorldPacket data;
2035 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2036 unitTarget->SendMessageToSet(&data, false);
2038 return;
2040 default:
2042 // If not exist data for dest location - return
2043 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2045 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2046 return;
2048 // Init dest coordinates
2049 uint32 mapid = m_caster->GetMapId();
2050 float x = m_targets.m_destX;
2051 float y = m_targets.m_destY;
2052 float z = m_targets.m_destZ;
2053 float orientation = unitTarget->GetOrientation();
2054 // Teleport
2055 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2056 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
2057 else
2059 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2060 WorldPacket data;
2061 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2062 unitTarget->SendMessageToSet(&data, false);
2064 return;
2068 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2069 switch ( m_spellInfo->Id )
2071 // Dimensional Ripper - Everlook
2072 case 23442:
2074 int32 r = irand(0, 119);
2075 if ( r >= 70 ) // 7/12 success
2077 if ( r < 100 ) // 4/12 evil twin
2078 m_caster->CastSpell(m_caster,23445,true);
2079 else // 1/12 fire
2080 m_caster->CastSpell(m_caster,23449,true);
2082 return;
2084 // Ultrasafe Transporter: Toshley's Station
2085 case 36941:
2087 if ( roll_chance_i(50) ) // 50% success
2089 int32 rand_eff = urand(1,7);
2090 switch ( rand_eff )
2092 case 1:
2093 // soul split - evil
2094 m_caster->CastSpell(m_caster,36900,true);
2095 break;
2096 case 2:
2097 // soul split - good
2098 m_caster->CastSpell(m_caster,36901,true);
2099 break;
2100 case 3:
2101 // Increase the size
2102 m_caster->CastSpell(m_caster,36895,true);
2103 break;
2104 case 4:
2105 // Decrease the size
2106 m_caster->CastSpell(m_caster,36893,true);
2107 break;
2108 case 5:
2109 // Transform
2111 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2112 m_caster->CastSpell(m_caster,36897,true);
2113 else
2114 m_caster->CastSpell(m_caster,36899,true);
2115 break;
2117 case 6:
2118 // chicken
2119 m_caster->CastSpell(m_caster,36940,true);
2120 break;
2121 case 7:
2122 // evil twin
2123 m_caster->CastSpell(m_caster,23445,true);
2124 break;
2127 return;
2129 // Dimensional Ripper - Area 52
2130 case 36890:
2132 if ( roll_chance_i(50) ) // 50% success
2134 int32 rand_eff = urand(1,4);
2135 switch ( rand_eff )
2137 case 1:
2138 // soul split - evil
2139 m_caster->CastSpell(m_caster,36900,true);
2140 break;
2141 case 2:
2142 // soul split - good
2143 m_caster->CastSpell(m_caster,36901,true);
2144 break;
2145 case 3:
2146 // Increase the size
2147 m_caster->CastSpell(m_caster,36895,true);
2148 break;
2149 case 4:
2150 // Transform
2152 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2153 m_caster->CastSpell(m_caster,36897,true);
2154 else
2155 m_caster->CastSpell(m_caster,36899,true);
2156 break;
2160 return;
2165 void Spell::EffectApplyAura(uint32 i)
2167 if(!unitTarget)
2168 return;
2170 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2171 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2172 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2173 return;
2175 Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
2176 if(!caster)
2177 return;
2179 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2181 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2183 // Now Reduce spell duration using data received at spell hit
2184 int32 duration = Aur->GetAuraMaxDuration();
2185 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2186 Aur->setDiminishGroup(m_diminishGroup);
2188 // if Aura removed and deleted, do not continue.
2189 if(duration== 0 && !(Aur->IsPermanent()))
2191 delete Aur;
2192 return;
2195 if(duration != Aur->GetAuraMaxDuration())
2197 Aur->SetAuraMaxDuration(duration);
2198 Aur->SetAuraDuration(duration);
2201 bool added = unitTarget->AddAura(Aur);
2203 // Aura not added and deleted in AddAura call;
2204 if (!added)
2205 return;
2207 // found crash at character loading, broken pointer to Aur...
2208 // Aur was deleted in AddAura()...
2209 if(!Aur)
2210 return;
2212 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2213 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2214 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2217 void Spell::EffectUnlearnSpecialization( uint32 i )
2219 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2220 return;
2222 Player *_player = (Player*)unitTarget;
2223 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2225 _player->removeSpell(spellToUnlearn);
2227 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2230 void Spell::EffectPowerDrain(uint32 i)
2232 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2233 return;
2235 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2237 if(!unitTarget)
2238 return;
2239 if(!unitTarget->isAlive())
2240 return;
2241 if(unitTarget->getPowerType() != drain_power)
2242 return;
2243 if(damage < 0)
2244 return;
2246 uint32 curPower = unitTarget->GetPower(drain_power);
2248 //add spell damage bonus
2249 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2251 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2252 uint32 power = damage;
2253 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2254 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2256 int32 new_damage;
2257 if(curPower < power)
2258 new_damage = curPower;
2259 else
2260 new_damage = power;
2262 unitTarget->ModifyPower(drain_power,-new_damage);
2264 // Don`t restore from self drain
2265 if(drain_power == POWER_MANA && m_caster != unitTarget)
2267 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2268 if(manaMultiplier==0)
2269 manaMultiplier = 1;
2271 if(Player *modOwner = m_caster->GetSpellModOwner())
2272 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2274 int32 gain = int32(new_damage*manaMultiplier);
2276 m_caster->ModifyPower(POWER_MANA,gain);
2277 //send log
2278 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2282 void Spell::EffectSendEvent(uint32 EffectIndex)
2284 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2286 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2287 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2289 switch(m_spellInfo->Id)
2291 case 23333: // Pickup Horde Flag
2292 /*do not uncomment .
2293 if(bg->GetTypeID()==BATTLEGROUND_WS)
2294 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2295 sLog.outDebug("Send Event Horde Flag Picked Up");
2296 break;
2297 /* not used :
2298 case 23334: // Drop Horde Flag
2299 if(bg->GetTypeID()==BATTLEGROUND_WS)
2300 bg->EventPlayerDroppedFlag((Player*)m_caster);
2301 sLog.outDebug("Drop Horde Flag");
2302 break;
2304 case 23335: // Pickup Alliance Flag
2305 /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
2306 if(bg->GetTypeID()==BATTLEGROUND_WS)
2307 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2308 sLog.outDebug("Send Event Alliance Flag Picked Up");
2309 break;
2310 /* not used :
2311 case 23336: // Drop Alliance Flag
2312 if(bg->GetTypeID()==BATTLEGROUND_WS)
2313 bg->EventPlayerDroppedFlag((Player*)m_caster);
2314 sLog.outDebug("Drop Alliance Flag");
2315 break;
2316 case 23385: // Alliance Flag Returns
2317 if(bg->GetTypeID()==BATTLEGROUND_WS)
2318 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2319 sLog.outDebug("Alliance Flag Returned");
2320 break;
2321 case 23386: // Horde Flag Returns
2322 if(bg->GetTypeID()==BATTLEGROUND_WS)
2323 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2324 sLog.outDebug("Horde Flag Returned");
2325 break;*/
2326 case 34976:
2328 if(bg->GetTypeID()==BATTLEGROUND_EY)
2329 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2331 break;
2332 default:
2333 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2334 break;
2338 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2339 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2342 void Spell::EffectPowerBurn(uint32 i)
2344 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2345 return;
2347 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2349 if(!unitTarget)
2350 return;
2351 if(!unitTarget->isAlive())
2352 return;
2353 if(unitTarget->getPowerType()!=powertype)
2354 return;
2355 if(damage < 0)
2356 return;
2358 int32 curPower = int32(unitTarget->GetPower(powertype));
2360 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2361 uint32 power = damage;
2362 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2363 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2365 int32 new_damage = (curPower < power) ? curPower : power;
2367 unitTarget->ModifyPower(powertype,-new_damage);
2368 float multiplier = m_spellInfo->EffectMultipleValue[i];
2370 if(Player *modOwner = m_caster->GetSpellModOwner())
2371 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2373 new_damage = int32(new_damage*multiplier);
2374 m_damage+=new_damage;
2377 void Spell::EffectHeal( uint32 /*i*/ )
2379 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2381 // Try to get original caster
2382 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2384 // Skip if m_originalCaster not available
2385 if (!caster)
2386 return;
2388 int32 addhealth = damage;
2390 // Vessel of the Naaru (Vial of the Sunwell trinket)
2391 if (m_spellInfo->Id == 45064)
2393 // Amount of heal - depends from stacked Holy Energy
2394 int damageAmount = 0;
2395 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2396 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2397 if((*i)->GetId() == 45062)
2398 damageAmount+=(*i)->GetModifier()->m_amount;
2399 if (damageAmount)
2400 m_caster->RemoveAurasDueToSpell(45062);
2402 addhealth += damageAmount;
2404 // Swiftmend - consumes Regrowth or Rejuvenation
2405 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2407 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2408 // find most short by duration
2409 Aura *targetAura = NULL;
2410 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2412 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2413 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2415 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2416 targetAura = *i;
2420 if(!targetAura)
2422 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2423 return;
2425 int idx = 0;
2426 while(idx < 3)
2428 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2429 break;
2430 idx++;
2433 int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
2434 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2435 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2437 addhealth += tickheal * tickcount;
2439 else
2440 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
2442 m_healing+=addhealth;
2446 void Spell::EffectHealPct( uint32 /*i*/ )
2448 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2450 // Try to get original caster
2451 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2453 // Skip if m_originalCaster not available
2454 if (!caster)
2455 return;
2457 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2458 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2460 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2461 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2463 if(caster->GetTypeId()==TYPEID_PLAYER)
2464 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2465 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2469 void Spell::EffectHealMechanical( uint32 /*i*/ )
2471 // Mechanic creature type should be correctly checked by targetCreatureType field
2472 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2474 // Try to get original caster
2475 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2477 // Skip if m_originalCaster not available
2478 if (!caster)
2479 return;
2481 uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
2482 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2483 unitTarget->ModifyHealth( int32(damage) );
2487 void Spell::EffectHealthLeech(uint32 i)
2489 if(!unitTarget)
2490 return;
2491 if(!unitTarget->isAlive())
2492 return;
2494 if(damage < 0)
2495 return;
2497 sLog.outDebug("HealthLeech :%i", damage);
2499 float multiplier = m_spellInfo->EffectMultipleValue[i];
2501 if(Player *modOwner = m_caster->GetSpellModOwner())
2502 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2504 int32 new_damage = int32(damage*multiplier);
2505 uint32 curHealth = unitTarget->GetHealth();
2506 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2507 if(curHealth < new_damage)
2508 new_damage = curHealth;
2510 if(m_caster->isAlive())
2512 new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
2514 m_caster->ModifyHealth(new_damage);
2516 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2517 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2519 // m_healthLeech+=tmpvalue;
2520 // m_damage+=new_damage;
2523 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2525 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2526 return;
2528 Player* player = (Player*)unitTarget;
2530 uint32 newitemid = itemtype;
2531 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2532 if(!pProto)
2534 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2535 return;
2538 uint32 num_to_add;
2540 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2541 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2543 int32 basePoints = m_currentBasePoints[i];
2544 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2545 if (randomPoints)
2546 num_to_add = basePoints + irand(1, randomPoints);
2547 else
2548 num_to_add = basePoints + 1;
2550 else if (pProto->MaxCount == 1)
2551 num_to_add = 1;
2552 else if(player->getLevel() >= m_spellInfo->spellLevel)
2554 int32 basePoints = m_currentBasePoints[i];
2555 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2556 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2558 else
2559 num_to_add = 2;
2561 if (num_to_add < 1)
2562 num_to_add = 1;
2563 if (num_to_add > pProto->GetMaxStackSize())
2564 num_to_add = pProto->GetMaxStackSize();
2566 // init items_count to 1, since 1 item will be created regardless of specialization
2567 int items_count=1;
2568 // the chance to create additional items
2569 float additionalCreateChance=0.0f;
2570 // the maximum number of created additional items
2571 uint8 additionalMaxNum=0;
2572 // get the chance and maximum number for creating extra items
2573 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2575 // roll with this chance till we roll not to create or we create the max num
2576 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2577 ++items_count;
2580 // really will be created more items
2581 num_to_add *= items_count;
2583 // can the player store the new item?
2584 ItemPosCountVec dest;
2585 uint32 no_space = 0;
2586 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2587 if( msg != EQUIP_ERR_OK )
2589 // convert to possible store amount
2590 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2591 num_to_add -= no_space;
2592 else
2594 // if not created by another reason from full inventory or unique items amount limitation
2595 player->SendEquipError( msg, NULL, NULL );
2596 return;
2600 if(num_to_add)
2602 // create the new item and store it
2603 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2605 // was it successful? return error if not
2606 if(!pItem)
2608 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2609 return;
2612 // set the "Crafted by ..." property of the item
2613 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2614 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2616 // send info to the client
2617 if(pItem)
2618 player->SendNewItem(pItem, num_to_add, true, true);
2620 // we succeeded in creating at least one item, so a levelup is possible
2621 player->UpdateCraftSkill(m_spellInfo->Id);
2624 // for battleground marks send by mail if not add all expected
2625 if(no_space > 0 )
2627 BattleGroundTypeId bgType;
2628 switch(m_spellInfo->Id)
2630 case SPELL_AV_MARK_WINNER:
2631 case SPELL_AV_MARK_LOSER:
2632 bgType = BATTLEGROUND_AV;
2633 break;
2634 case SPELL_WS_MARK_WINNER:
2635 case SPELL_WS_MARK_LOSER:
2636 bgType = BATTLEGROUND_WS;
2637 break;
2638 case SPELL_AB_MARK_WINNER:
2639 case SPELL_AB_MARK_LOSER:
2640 bgType = BATTLEGROUND_AB;
2641 break;
2642 default:
2643 return;
2646 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2647 bg->SendRewardMarkByMail(player,newitemid,no_space);
2651 void Spell::EffectCreateItem(uint32 i)
2653 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2656 void Spell::EffectCreateItem2(uint32 i)
2658 // special case: generate using spell_loot_template
2659 if(!m_spellInfo->EffectItemType[i])
2661 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
2662 return;
2664 // create some random items
2665 ((Player*)m_caster)->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
2666 return;
2668 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2671 void Spell::EffectPersistentAA(uint32 i)
2673 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2675 if(Player* modOwner = m_caster->GetSpellModOwner())
2676 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2678 int32 duration = GetSpellDuration(m_spellInfo);
2679 DynamicObject* dynObj = new DynamicObject;
2680 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))
2682 delete dynObj;
2683 return;
2685 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2686 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2687 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2688 m_caster->AddDynObject(dynObj);
2689 dynObj->GetMap()->Add(dynObj);
2692 void Spell::EffectEnergize(uint32 i)
2694 if(!unitTarget)
2695 return;
2696 if(!unitTarget->isAlive())
2697 return;
2699 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2700 return;
2702 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2704 // Some level depends spells
2705 int multiplier = 0;
2706 int level_diff = 0;
2707 switch (m_spellInfo->Id)
2709 // Restore Energy
2710 case 9512:
2711 level_diff = m_caster->getLevel() - 40;
2712 multiplier = 2;
2713 break;
2714 // Blood Fury
2715 case 24571:
2716 level_diff = m_caster->getLevel() - 60;
2717 multiplier = 10;
2718 break;
2719 // Burst of Energy
2720 case 24532:
2721 level_diff = m_caster->getLevel() - 60;
2722 multiplier = 4;
2723 break;
2724 default:
2725 break;
2728 if (level_diff > 0)
2729 damage -= multiplier * level_diff;
2731 if(damage < 0)
2732 return;
2734 if(unitTarget->GetMaxPower(power) == 0)
2735 return;
2737 unitTarget->ModifyPower(power,damage);
2738 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2740 // Mad Alchemist's Potion
2741 if (m_spellInfo->Id == 45051)
2743 // find elixirs on target
2744 uint32 elixir_mask = 0;
2745 Unit::AuraMap& Auras = unitTarget->GetAuras();
2746 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2748 uint32 spell_id = itr->second->GetId();
2749 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2750 elixir_mask |= mask;
2753 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2754 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2756 // get all available elixirs by mask and spell level
2757 std::vector<uint32> elixirs;
2758 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2759 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2761 if (itr->second & elixir_mask)
2763 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2764 continue;
2766 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2767 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2768 continue;
2770 elixirs.push_back(itr->first);
2774 if (!elixirs.empty())
2776 // cast random elixir on target
2777 uint32 rand_spell = urand(0,elixirs.size()-1);
2778 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2783 void Spell::EffectEnergisePct(uint32 i)
2785 if(!unitTarget)
2786 return;
2787 if(!unitTarget->isAlive())
2788 return;
2790 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2791 return;
2793 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2795 uint32 maxPower = unitTarget->GetMaxPower(power);
2796 if(maxPower == 0)
2797 return;
2799 uint32 gain = damage * maxPower / 100;
2800 unitTarget->ModifyPower(power, gain);
2801 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2804 void Spell::SendLoot(uint64 guid, LootType loottype)
2806 Player* player = (Player*)m_caster;
2807 if (!player)
2808 return;
2810 if (gameObjTarget)
2812 if (Script->GOHello(player, gameObjTarget))
2813 return;
2815 switch (gameObjTarget->GetGoType())
2817 case GAMEOBJECT_TYPE_DOOR:
2818 case GAMEOBJECT_TYPE_BUTTON:
2819 gameObjTarget->UseDoorOrButton();
2820 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2821 return;
2823 case GAMEOBJECT_TYPE_QUESTGIVER:
2824 // start or end quest
2825 player->PrepareQuestMenu(guid);
2826 player->SendPreparedQuest(guid);
2827 return;
2829 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2830 // triggering linked GO
2831 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2832 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2833 return;
2835 case GAMEOBJECT_TYPE_GOOBER:
2836 // goober_scripts can be triggered if the player don't have the quest
2837 if (gameObjTarget->GetGOInfo()->goober.eventId)
2839 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2840 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2843 // cast goober spell
2844 if (gameObjTarget->GetGOInfo()->goober.questId)
2845 ///Quest require to be active for GO using
2846 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2847 return;
2849 gameObjTarget->AddUniqueUse(player);
2850 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2852 //TODO? Objective counting called without spell check but with quest objective check
2853 // if send spell id then this line will duplicate to spell casting call (double counting)
2854 // So we or have this line and not required in quest_template have reqSpellIdN
2855 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2856 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2858 // triggering linked GO
2859 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2860 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2862 return;
2864 case GAMEOBJECT_TYPE_CHEST:
2865 // TODO: possible must be moved to loot release (in different from linked triggering)
2866 if (gameObjTarget->GetGOInfo()->chest.eventId)
2868 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2869 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2872 // triggering linked GO
2873 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2874 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2876 // Don't return, let loots been taken
2880 // Send loot
2881 player->SendLoot(guid, loottype);
2884 void Spell::EffectOpenLock(uint32 /*i*/)
2886 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2888 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2889 return;
2892 Player* player = (Player*)m_caster;
2894 LootType loottype = LOOT_CORPSE;
2895 uint32 lockId = 0;
2896 uint64 guid = 0;
2898 // Get lockId
2899 if(gameObjTarget)
2901 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2902 // Arathi Basin banner opening !
2903 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2904 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2906 //isAllowUseBattleGroundObject() already called in CanCast()
2907 // in battleground check
2908 if(BattleGround *bg = player->GetBattleGround())
2910 // check if it's correct bg
2911 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2912 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2913 return;
2916 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2918 //isAllowUseBattleGroundObject() already called in CanCast()
2919 // in battleground check
2920 if(BattleGround *bg = player->GetBattleGround())
2922 if(bg->GetTypeID() == BATTLEGROUND_EY)
2923 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2924 return;
2927 lockId = gameObjTarget->GetLockId();
2928 guid = gameObjTarget->GetGUID();
2930 else if(itemTarget)
2932 lockId = itemTarget->GetProto()->LockID;
2933 guid = itemTarget->GetGUID();
2935 else
2937 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2938 return;
2941 if(!lockId) // possible case for GO and maybe for items.
2943 SendLoot(guid, loottype);
2944 return;
2947 // Get LockInfo
2948 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2950 if (!lockInfo)
2952 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2953 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2954 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2955 return;
2958 // check key
2959 for(int i = 0; i < 8; ++i)
2961 // Type==1 This means lockInfo->Index[i] is an item
2962 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2964 SendLoot(guid, loottype);
2965 return;
2969 uint32 SkillId = 0;
2970 // Check and skill-up skill
2971 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2972 SkillId = m_spellInfo->EffectMiscValue[1];
2973 // pickpocketing spells
2974 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2975 SkillId = SKILL_LOCKPICKING;
2977 // skill bonus provided by casting spell (mostly item spells)
2978 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2980 uint32 reqSkillValue = lockInfo->Skill[0];
2982 if(lockInfo->Skill[1]) // required pick lock skill applying
2984 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2986 SendCastResult(SPELL_FAILED_FIZZLE);
2987 return;
2990 reqSkillValue = lockInfo->Skill[1];
2992 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2994 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2995 return;
2998 if ( SkillId )
3000 loottype = LOOT_SKINNING;
3001 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
3003 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3004 return;
3007 // update skill if really known
3008 if(uint32 SkillValue = player->GetPureSkillValue(SkillId))
3010 if(gameObjTarget)
3012 // Allow one skill-up until respawned
3013 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3014 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3015 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3017 else if(itemTarget)
3019 // Do one skill-up
3020 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3025 SendLoot(guid, loottype);
3028 void Spell::EffectSummonChangeItem(uint32 i)
3030 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3031 return;
3033 Player *player = (Player*)m_caster;
3035 // applied only to using item
3036 if(!m_CastItem)
3037 return;
3039 // ... only to item in own inventory/bank/equip_slot
3040 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3041 return;
3043 uint32 newitemid = m_spellInfo->EffectItemType[i];
3044 if(!newitemid)
3045 return;
3047 uint16 pos = m_CastItem->GetPos();
3049 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3050 if( !pNewItem )
3051 return;
3053 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3055 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3056 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3059 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3061 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3062 player->DurabilityLoss(pNewItem, loosePercent);
3065 if( player->IsInventoryPos( pos ) )
3067 ItemPosCountVec dest;
3068 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3069 if( msg == EQUIP_ERR_OK )
3071 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3073 // prevent crash at access and unexpected charges counting with item update queue corrupt
3074 if(m_CastItem==m_targets.getItemTarget())
3075 m_targets.setItemTarget(NULL);
3077 m_CastItem = NULL;
3079 player->StoreItem( dest, pNewItem, true);
3080 return;
3083 else if( player->IsBankPos ( pos ) )
3085 ItemPosCountVec dest;
3086 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3087 if( msg == EQUIP_ERR_OK )
3089 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3091 // prevent crash at access and unexpected charges counting with item update queue corrupt
3092 if(m_CastItem==m_targets.getItemTarget())
3093 m_targets.setItemTarget(NULL);
3095 m_CastItem = NULL;
3097 player->BankItem( dest, pNewItem, true);
3098 return;
3101 else if( player->IsEquipmentPos ( pos ) )
3103 uint16 dest;
3104 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3105 if( msg == EQUIP_ERR_OK )
3107 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3109 // prevent crash at access and unexpected charges counting with item update queue corrupt
3110 if(m_CastItem==m_targets.getItemTarget())
3111 m_targets.setItemTarget(NULL);
3113 m_CastItem = NULL;
3115 player->EquipItem( dest, pNewItem, true);
3116 player->AutoUnequipOffhandIfNeed();
3117 return;
3121 // fail
3122 delete pNewItem;
3125 void Spell::EffectOpenSecretSafe(uint32 i)
3127 EffectOpenLock(i); //no difference for now
3130 void Spell::EffectProficiency(uint32 /*i*/)
3132 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3133 return;
3134 Player *p_target = (Player*)unitTarget;
3136 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3137 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3139 p_target->AddWeaponProficiency(subClassMask);
3140 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3142 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3144 p_target->AddArmorProficiency(subClassMask);
3145 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3149 void Spell::EffectApplyAreaAura(uint32 i)
3151 if(!unitTarget)
3152 return;
3153 if(!unitTarget->isAlive())
3154 return;
3156 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3157 unitTarget->AddAura(Aur);
3160 void Spell::EffectSummonType(uint32 i)
3162 switch(m_spellInfo->EffectMiscValueB[i])
3164 case SUMMON_TYPE_GUARDIAN:
3165 case SUMMON_TYPE_POSESSED:
3166 case SUMMON_TYPE_POSESSED2:
3167 case SUMMON_TYPE_FORCE_OF_NATURE:
3168 case SUMMON_TYPE_GUARDIAN2:
3169 EffectSummonGuardian(i);
3170 break;
3171 case SUMMON_TYPE_WILD:
3172 EffectSummonWild(i);
3173 break;
3174 case SUMMON_TYPE_DEMON:
3175 EffectSummonDemon(i);
3176 break;
3177 case SUMMON_TYPE_SUMMON:
3178 EffectSummon(i);
3179 break;
3180 case SUMMON_TYPE_CRITTER:
3181 case SUMMON_TYPE_CRITTER2:
3182 case SUMMON_TYPE_CRITTER3:
3183 EffectSummonCritter(i);
3184 break;
3185 case SUMMON_TYPE_TOTEM_SLOT1:
3186 case SUMMON_TYPE_TOTEM_SLOT2:
3187 case SUMMON_TYPE_TOTEM_SLOT3:
3188 case SUMMON_TYPE_TOTEM_SLOT4:
3189 case SUMMON_TYPE_TOTEM:
3190 EffectSummonTotem(i);
3191 break;
3192 case SUMMON_TYPE_UNKNOWN1:
3193 case SUMMON_TYPE_UNKNOWN2:
3194 case SUMMON_TYPE_UNKNOWN3:
3195 case SUMMON_TYPE_UNKNOWN4:
3196 case SUMMON_TYPE_UNKNOWN5:
3197 break;
3198 default:
3199 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3200 break;
3204 void Spell::EffectSummon(uint32 i)
3206 if(m_caster->GetPetGUID())
3207 return;
3209 if(!unitTarget)
3210 return;
3211 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3212 if(!pet_entry)
3213 return;
3214 uint32 level = m_caster->getLevel();
3215 Pet* spawnCreature = new Pet(SUMMON_PET);
3217 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3219 // set timer for unsummon
3220 int32 duration = GetSpellDuration(m_spellInfo);
3221 if(duration > 0)
3222 spawnCreature->SetDuration(duration);
3224 return;
3227 Map *map = m_caster->GetMap();
3228 uint32 pet_number = objmgr.GeneratePetNumber();
3229 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_caster->GetPhaseMask(),
3230 m_spellInfo->EffectMiscValue[i], pet_number))
3232 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3233 delete spawnCreature;
3234 return;
3237 // Summon in dest location
3238 float x,y,z;
3239 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3241 x = m_targets.m_destX;
3242 y = m_targets.m_destY;
3243 z = m_targets.m_destZ;
3245 else
3246 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3248 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3250 if(!spawnCreature->IsPositionValid())
3252 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3253 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3254 delete spawnCreature;
3255 return;
3258 // set timer for unsummon
3259 int32 duration = GetSpellDuration(m_spellInfo);
3260 if(duration > 0)
3261 spawnCreature->SetDuration(duration);
3263 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3264 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3265 spawnCreature->setPowerType(POWER_MANA);
3266 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3267 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3268 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3269 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3270 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3271 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3272 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3273 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3274 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3276 spawnCreature->InitStatsForLevel(level);
3278 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3280 spawnCreature->AIM_Initialize();
3281 spawnCreature->InitPetCreateSpells();
3282 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3283 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3285 std::string name = m_caster->GetName();
3286 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3287 spawnCreature->SetName( name );
3289 map->Add((Creature*)spawnCreature);
3291 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3293 m_caster->SetPet(spawnCreature);
3294 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3295 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3296 ((Player*)m_caster)->PetSpellInitialize();
3300 void Spell::EffectLearnSpell(uint32 i)
3302 if(!unitTarget)
3303 return;
3305 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3307 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3308 EffectLearnPetSpell(i);
3310 return;
3313 Player *player = (Player*)unitTarget;
3315 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3316 player->learnSpell(spellToLearn,false);
3318 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3321 void Spell::EffectDispel(uint32 i)
3323 if(!unitTarget)
3324 return;
3326 // Fill possible dispell list
3327 std::vector <Aura *> dispel_list;
3329 // Create dispel mask by dispel type
3330 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3331 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3332 Unit::AuraMap const& auras = unitTarget->GetAuras();
3333 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3335 Aura *aur = (*itr).second;
3336 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3338 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3340 bool positive = true;
3341 if (!aur->IsPositive())
3342 positive = false;
3343 else
3344 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3346 // do not remove positive auras if friendly target
3347 // negative auras if non-friendly target
3348 if(positive == unitTarget->IsFriendlyTo(m_caster))
3349 continue;
3351 // Add aura to dispel list
3352 dispel_list.push_back(aur);
3355 // Ok if exist some buffs for dispel try dispel it
3356 if (!dispel_list.empty())
3358 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3359 std::list < uint32 > fail_list; // spell_id
3360 int32 list_size = dispel_list.size();
3361 // Dispell N = damage buffs (or while exist buffs for dispel)
3362 for (int32 count=0; count < damage && list_size > 0; ++count)
3364 // Random select buff for dispel
3365 Aura *aur = dispel_list[urand(0, list_size-1)];
3367 SpellEntry const* spellInfo = aur->GetSpellProto();
3368 // Base dispel chance
3369 // TODO: possible chance depend from spell level??
3370 int32 miss_chance = 0;
3371 // Apply dispel mod from aura caster
3372 if (Unit *caster = aur->GetCaster())
3374 if ( Player* modOwner = caster->GetSpellModOwner() )
3375 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3377 // Try dispel
3378 if (roll_chance_i(miss_chance))
3379 fail_list.push_back(aur->GetId());
3380 else
3381 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3382 // Remove buff from list for prevent doubles
3383 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3385 Aura *dispeled = *j;
3386 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3388 j = dispel_list.erase(j);
3389 --list_size;
3391 else
3392 ++j;
3395 // Send success log and really remove auras
3396 if (!success_list.empty())
3398 int32 count = success_list.size();
3399 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3400 data.append(unitTarget->GetPackGUID()); // Victim GUID
3401 data.append(m_caster->GetPackGUID()); // Caster GUID
3402 data << uint32(m_spellInfo->Id); // Dispell spell id
3403 data << uint8(0); // not used
3404 data << uint32(count); // count
3405 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3407 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3408 data << uint32(spellInfo->Id); // Spell Id
3409 data << uint8(0); // 0 - dispeled !=0 cleansed
3410 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3412 m_caster->SendMessageToSet(&data, true);
3414 // On succes dispel
3415 // Devour Magic
3416 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3418 uint32 heal_spell = 0;
3419 switch (m_spellInfo->Id)
3421 case 19505: heal_spell = 19658; break;
3422 case 19731: heal_spell = 19732; break;
3423 case 19734: heal_spell = 19733; break;
3424 case 19736: heal_spell = 19735; break;
3425 case 27276: heal_spell = 27278; break;
3426 case 27277: heal_spell = 27279; break;
3427 default:
3428 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3429 break;
3431 if (heal_spell)
3432 m_caster->CastSpell(m_caster, heal_spell, true);
3435 // Send fail log to client
3436 if (!fail_list.empty())
3438 // Failed to dispell
3439 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3440 data << uint64(m_caster->GetGUID()); // Caster GUID
3441 data << uint64(unitTarget->GetGUID()); // Victim GUID
3442 data << uint32(m_spellInfo->Id); // Dispell spell id
3443 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3444 data << uint32(*j); // Spell Id
3445 m_caster->SendMessageToSet(&data, true);
3450 void Spell::EffectDualWield(uint32 /*i*/)
3452 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3453 ((Player*)unitTarget)->SetCanDualWield(true);
3456 void Spell::EffectPull(uint32 /*i*/)
3458 // TODO: create a proper pull towards distract spell center for distract
3459 sLog.outDebug("WORLD: Spell Effect DUMMY");
3462 void Spell::EffectDistract(uint32 /*i*/)
3464 // Check for possible target
3465 if (!unitTarget || unitTarget->isInCombat())
3466 return;
3468 // target must be OK to do this
3469 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3470 return;
3472 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3474 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3476 // For players just turn them
3477 WorldPacket data;
3478 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3479 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3480 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3482 else
3484 // Set creature Distracted, Stop it, And turn it
3485 unitTarget->SetOrientation(angle);
3486 unitTarget->StopMoving();
3487 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3491 void Spell::EffectPickPocket(uint32 /*i*/)
3493 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3494 return;
3496 // victim must be creature and attackable
3497 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3498 return;
3500 // victim have to be alive and humanoid or undead
3501 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3503 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3505 if (chance > irand(0, 19))
3507 // Stealing successful
3508 //sLog.outDebug("Sending loot from pickpocket");
3509 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3511 else
3513 // Reveal action + get attack
3514 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3515 if (((Creature*)unitTarget)->AI())
3516 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3521 void Spell::EffectAddFarsight(uint32 i)
3523 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3524 int32 duration = GetSpellDuration(m_spellInfo);
3525 DynamicObject* dynObj = new DynamicObject;
3526 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))
3528 delete dynObj;
3529 return;
3531 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3532 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3533 m_caster->AddDynObject(dynObj);
3534 dynObj->GetMap()->Add(dynObj);
3535 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3536 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3539 void Spell::EffectSummonWild(uint32 i)
3541 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3542 if(!creature_entry)
3543 return;
3545 uint32 level = m_caster->getLevel();
3547 // level of creature summoned using engineering item based at engineering skill level
3548 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3550 ItemPrototype const *proto = m_CastItem->GetProto();
3551 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3553 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3554 if(skill202)
3556 level = skill202/5;
3561 // select center of summon position
3562 float center_x = m_targets.m_destX;
3563 float center_y = m_targets.m_destY;
3564 float center_z = m_targets.m_destZ;
3566 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3568 int32 amount = damage > 0 ? damage : 1;
3570 for(int32 count = 0; count < amount; ++count)
3572 float px, py, pz;
3573 // If dest location if present
3574 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3576 // Summon 1 unit in dest location
3577 if (count == 0)
3579 px = m_targets.m_destX;
3580 py = m_targets.m_destY;
3581 pz = m_targets.m_destZ;
3583 // Summon in random point all other units if location present
3584 else
3585 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3587 // Summon if dest location not present near caster
3588 else
3589 m_caster->GetClosePoint(px,py,pz,3.0f);
3591 int32 duration = GetSpellDuration(m_spellInfo);
3593 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3595 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3599 void Spell::EffectSummonGuardian(uint32 i)
3601 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3602 if(!pet_entry)
3603 return;
3605 // Jewelery statue case (totem like)
3606 if(m_spellInfo->SpellIconID==2056)
3608 EffectSummonTotem(i);
3609 return;
3612 // set timer for unsummon
3613 int32 duration = GetSpellDuration(m_spellInfo);
3615 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3616 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3617 // so this code hack in fact
3618 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3619 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3620 return; // find old guardian, ignore summon
3622 // in another case summon new
3623 uint32 level = m_caster->getLevel();
3625 // level of pet summoned using engineering item based at engineering skill level
3626 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3628 ItemPrototype const *proto = m_CastItem->GetProto();
3629 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3631 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3632 if(skill202)
3634 level = skill202/5;
3639 // select center of summon position
3640 float center_x = m_targets.m_destX;
3641 float center_y = m_targets.m_destY;
3642 float center_z = m_targets.m_destZ;
3644 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3646 int32 amount = damage > 0 ? damage : 1;
3648 for(int32 count = 0; count < amount; ++count)
3650 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3652 Map *map = m_caster->GetMap();
3653 uint32 pet_number = objmgr.GeneratePetNumber();
3654 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_caster->GetPhaseMask(),
3655 m_spellInfo->EffectMiscValue[i], pet_number))
3657 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3658 delete spawnCreature;
3659 return;
3662 float px, py, pz;
3663 // If dest location if present
3664 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3666 // Summon 1 unit in dest location
3667 if (count == 0)
3669 px = m_targets.m_destX;
3670 py = m_targets.m_destY;
3671 pz = m_targets.m_destZ;
3673 // Summon in random point all other units if location present
3674 else
3675 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3677 // Summon if dest location not present near caster
3678 else
3679 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3681 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3683 if(!spawnCreature->IsPositionValid())
3685 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3686 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3687 delete spawnCreature;
3688 return;
3691 if(duration > 0)
3692 spawnCreature->SetDuration(duration);
3694 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3695 spawnCreature->setPowerType(POWER_MANA);
3696 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3697 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3698 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3699 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3700 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3701 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3702 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3704 spawnCreature->InitStatsForLevel(level);
3705 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3707 spawnCreature->AIM_Initialize();
3709 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3710 ((Player*)m_caster)->AddGuardian(spawnCreature);
3712 map->Add((Creature*)spawnCreature);
3716 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3718 if(!unitTarget)
3719 return;
3721 if(unitTarget->isInFlight())
3722 return;
3724 uint32 mapid = m_caster->GetMapId();
3725 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3727 float fx,fy,fz;
3728 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3730 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3731 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
3732 else
3733 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3736 void Spell::EffectLearnSkill(uint32 i)
3738 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3739 return;
3741 if(damage < 0)
3742 return;
3744 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3745 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3746 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3749 void Spell::EffectAddHonor(uint32 /*i*/)
3751 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3752 return;
3754 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3756 // TODO: find formula for honor reward based on player's level!
3758 // now fixed only for level 70 players:
3759 if (((Player*)unitTarget)->getLevel() == 70)
3760 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3763 void Spell::EffectTradeSkill(uint32 /*i*/)
3765 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3766 return;
3767 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3768 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3769 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3772 void Spell::EffectEnchantItemPerm(uint32 effect_idx)
3774 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3775 return;
3776 if (!itemTarget)
3777 return;
3779 Player* p_caster = (Player*)m_caster;
3781 // not grow at item use at item case
3782 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3784 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3785 if (!enchant_id)
3786 return;
3788 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3789 if(!pEnchant)
3790 return;
3792 // item can be in trade slot and have owner diff. from caster
3793 Player* item_owner = itemTarget->GetOwner();
3794 if(!item_owner)
3795 return;
3797 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3799 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3800 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3801 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3802 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3805 // remove old enchanting before applying new if equipped
3806 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3808 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3810 // add new enchanting if equipped
3811 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3814 void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
3816 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3817 return;
3818 if (!itemTarget)
3819 return;
3821 Player* p_caster = (Player*)m_caster;
3823 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3824 if (!enchant_id)
3825 return;
3827 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3828 if(!pEnchant)
3829 return;
3831 // support only enchantings with add socket in this slot
3833 bool add_socket = false;
3834 for(int i = 0; i < 3; ++i)
3836 if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
3838 add_socket = true;
3839 break;
3842 if(!add_socket)
3844 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.",
3845 m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
3846 return;
3850 // item can be in trade slot and have owner diff. from caster
3851 Player* item_owner = itemTarget->GetOwner();
3852 if(!item_owner)
3853 return;
3855 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3857 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3858 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3859 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3860 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3863 // remove old enchanting before applying new if equipped
3864 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
3866 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3868 // add new enchanting if equipped
3869 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
3872 void Spell::EffectEnchantItemTmp(uint32 i)
3874 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3875 return;
3877 Player* p_caster = (Player*)m_caster;
3879 if(!itemTarget)
3880 return;
3882 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3884 // Shaman Rockbiter Weapon
3885 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3887 int32 enchnting_damage = m_currentBasePoints[1]+1;
3889 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3890 // with already applied percent bonus from Elemental Weapons talent
3891 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3892 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3893 switch(enchnting_damage)
3895 // Rank 1
3896 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3897 // Rank 2
3898 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3899 case 5: enchant_id = 3025; break; // 20%
3900 // Rank 3
3901 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3902 case 7: enchant_id = 3027; break; // 20%
3903 // Rank 4
3904 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3905 case 10: enchant_id = 503; break; // 14%
3906 case 11: enchant_id = 3031; break; // 20%
3907 // Rank 5
3908 case 15: enchant_id = 3035; break; // 0%
3909 case 16: enchant_id = 1663; break; // 7%
3910 case 17: enchant_id = 3033; break; // 14%
3911 case 18: enchant_id = 3034; break; // 20%
3912 // Rank 6
3913 case 28: enchant_id = 3038; break; // 0%
3914 case 29: enchant_id = 683; break; // 7%
3915 case 31: enchant_id = 3036; break; // 14%
3916 case 33: enchant_id = 3037; break; // 20%
3917 // Rank 7
3918 case 40: enchant_id = 3041; break; // 0%
3919 case 42: enchant_id = 1664; break; // 7%
3920 case 45: enchant_id = 3039; break; // 14%
3921 case 48: enchant_id = 3040; break; // 20%
3922 // Rank 8
3923 case 49: enchant_id = 3044; break; // 0%
3924 case 52: enchant_id = 2632; break; // 7%
3925 case 55: enchant_id = 3042; break; // 14%
3926 case 58: enchant_id = 3043; break; // 20%
3927 // Rank 9
3928 case 62: enchant_id = 2633; break; // 0%
3929 case 66: enchant_id = 3018; break; // 7%
3930 case 70: enchant_id = 3019; break; // 14%
3931 case 74: enchant_id = 3020; break; // 20%
3932 default:
3933 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3934 return;
3938 if (!enchant_id)
3940 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3941 return;
3944 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3945 if(!pEnchant)
3947 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3948 return;
3951 // select enchantment duration
3952 uint32 duration;
3954 // rogue family enchantments exception by duration
3955 if(m_spellInfo->Id==38615)
3956 duration = 1800; // 30 mins
3957 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3958 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3959 duration = 3600; // 1 hour
3960 // shaman family enchantments
3961 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3962 duration = 1800; // 30 mins
3963 // other cases with this SpellVisual already selected
3964 else if(m_spellInfo->SpellVisual[0]==215)
3965 duration = 1800; // 30 mins
3966 // some fishing pole bonuses
3967 else if(m_spellInfo->SpellVisual[0]==563)
3968 duration = 600; // 10 mins
3969 // shaman rockbiter enchantments
3970 else if(m_spellInfo->SpellVisual[0]==0)
3971 duration = 1800; // 30 mins
3972 else if(m_spellInfo->Id==29702)
3973 duration = 300; // 5 mins
3974 else if(m_spellInfo->Id==37360)
3975 duration = 300; // 5 mins
3976 // default case
3977 else
3978 duration = 3600; // 1 hour
3980 // item can be in trade slot and have owner diff. from caster
3981 Player* item_owner = itemTarget->GetOwner();
3982 if(!item_owner)
3983 return;
3985 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3987 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3988 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3989 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3990 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3993 // remove old enchanting before applying new if equipped
3994 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3996 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3998 // add new enchanting if equipped
3999 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
4002 void Spell::EffectTameCreature(uint32 /*i*/)
4004 if(m_caster->GetPetGUID())
4005 return;
4007 if(!unitTarget)
4008 return;
4010 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
4011 return;
4013 Creature* creatureTarget = (Creature*)unitTarget;
4015 if(creatureTarget->isPet())
4016 return;
4018 if(m_caster->getClass() != CLASS_HUNTER)
4019 return;
4021 // cast finish successfully
4022 //SendChannelUpdate(0);
4023 finish();
4025 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
4027 // kill original creature
4028 creatureTarget->setDeathState(JUST_DIED);
4029 creatureTarget->RemoveCorpse();
4030 creatureTarget->SetHealth(0); // just for nice GM-mode view
4032 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4034 // prepare visual effect for levelup
4035 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4037 // add to world
4038 pet->GetMap()->Add((Creature*)pet);
4040 // visual effect for levelup
4041 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4043 // caster have pet now
4044 m_caster->SetPet(pet);
4046 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4048 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4049 ((Player*)m_caster)->PetSpellInitialize();
4053 void Spell::EffectSummonPet(uint32 i)
4055 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4057 Pet *OldSummon = m_caster->GetPet();
4059 // if pet requested type already exist
4060 if( OldSummon )
4062 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4064 // pet in corpse state can't be summoned
4065 if( OldSummon->isDead() )
4066 return;
4068 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4069 OldSummon->SetMapId(m_caster->GetMapId());
4071 float px, py, pz;
4072 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4074 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4075 m_caster->GetMap()->Add((Creature*)OldSummon);
4077 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4079 ((Player*)m_caster)->PetSpellInitialize();
4081 return;
4084 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4085 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4086 else
4087 return;
4090 Pet* NewSummon = new Pet;
4092 // petentry==0 for hunter "call pet" (current pet summoned if any)
4093 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4095 if(NewSummon->getPetType()==SUMMON_PET)
4097 // Remove Demonic Sacrifice auras (known pet)
4098 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4099 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4101 if((*itr)->GetModifier()->m_miscvalue==2228)
4103 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4104 itr = auraClassScripts.begin();
4106 else
4107 ++itr;
4111 return;
4114 // not error in case fail hunter call pet
4115 if(!petentry)
4117 delete NewSummon;
4118 return;
4121 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4123 if(!cInfo)
4125 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4126 delete NewSummon;
4127 return;
4130 Map *map = m_caster->GetMap();
4131 uint32 pet_number = objmgr.GeneratePetNumber();
4132 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
4133 petentry, pet_number))
4135 delete NewSummon;
4136 return;
4139 float px, py, pz;
4140 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4142 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4144 if(!NewSummon->IsPositionValid())
4146 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4147 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4148 delete NewSummon;
4149 return;
4152 uint32 petlevel = m_caster->getLevel();
4153 NewSummon->setPetType(SUMMON_PET);
4155 uint32 faction = m_caster->getFaction();
4156 if(m_caster->GetTypeId() == TYPEID_UNIT)
4158 if ( ((Creature*)m_caster)->isTotem() )
4159 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4160 else
4161 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4164 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4165 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4166 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4167 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4168 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4169 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4170 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4171 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4172 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4173 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4175 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4176 // this enables pet details window (Shift+P)
4178 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4179 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4180 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4182 NewSummon->InitStatsForLevel(petlevel);
4183 NewSummon->InitPetCreateSpells();
4184 NewSummon->InitTalentForLevel();
4186 if(NewSummon->getPetType()==SUMMON_PET)
4188 // Remove Demonic Sacrifice auras (new pet)
4189 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4190 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4192 if((*itr)->GetModifier()->m_miscvalue==2228)
4194 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4195 itr = auraClassScripts.begin();
4197 else
4198 ++itr;
4201 // generate new name for summon pet
4202 std::string new_name=objmgr.GeneratePetName(petentry);
4203 if(!new_name.empty())
4204 NewSummon->SetName(new_name);
4206 else if(NewSummon->getPetType()==HUNTER_PET)
4207 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4209 NewSummon->AIM_Initialize();
4210 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4211 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4213 map->Add((Creature*)NewSummon);
4215 m_caster->SetPet(NewSummon);
4216 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4218 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4220 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4221 ((Player*)m_caster)->PetSpellInitialize();
4225 void Spell::EffectLearnPetSpell(uint32 i)
4227 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4228 return;
4230 Player *_player = (Player*)m_caster;
4232 Pet *pet = _player->GetPet();
4233 if(!pet)
4234 return;
4235 if(!pet->isAlive())
4236 return;
4238 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4239 if(!learn_spellproto)
4240 return;
4242 pet->learnSpell(learn_spellproto->Id);
4244 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4245 _player->PetSpellInitialize();
4248 void Spell::EffectTaunt(uint32 /*i*/)
4250 // this effect use before aura Taunt apply for prevent taunt already attacking target
4251 // for spell as marked "non effective at already attacking target"
4252 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4254 if(unitTarget->getVictim()==m_caster)
4256 SendCastResult(SPELL_FAILED_DONT_REPORT);
4257 return;
4261 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4262 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4263 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4266 void Spell::EffectWeaponDmg(uint32 i)
4268 if(!unitTarget)
4269 return;
4270 if(!unitTarget->isAlive())
4271 return;
4273 // multiple weapon dmg effect workaround
4274 // execute only the last weapon damage
4275 // and handle all effects at once
4276 for (int j = 0; j < 3; j++)
4278 switch(m_spellInfo->Effect[j])
4280 case SPELL_EFFECT_WEAPON_DAMAGE:
4281 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4282 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4283 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4284 if (j < i) // we must calculate only at last weapon effect
4285 return;
4286 break;
4290 // some spell specific modifiers
4291 bool customBonusDamagePercentMod = false;
4292 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4293 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4294 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4295 bool normalized = false;
4297 int32 spell_bonus = 0; // bonus specific for spell
4298 switch(m_spellInfo->SpellFamilyName)
4300 case SPELLFAMILY_WARRIOR:
4302 // Whirlwind, single only spell with 2 weapon white damage apply if have
4303 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4305 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4306 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4308 // Devastate bonus and sunder armor refresh
4309 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4311 uint32 stack = 0;
4312 // Need refresh all Sunder Armor auras from this caster
4313 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4314 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4316 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4317 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4318 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4319 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4321 (*itr).second->RefreshAura();
4322 stack = (*itr).second->GetStackAmount();
4325 if (stack)
4326 spell_bonus += stack * CalculateDamage(2, unitTarget);
4328 break;
4330 case SPELLFAMILY_ROGUE:
4332 // Ambush
4333 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4335 customBonusDamagePercentMod = true;
4336 bonusDamagePercentMod = 2.5f; // 250%
4338 // Mutilate (for each hand)
4339 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4341 bool found = false;
4342 // fast check
4343 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4344 found = true;
4345 // full aura scan
4346 else
4348 Unit::AuraMap const& auras = unitTarget->GetAuras();
4349 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4351 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4353 found = true;
4354 break;
4359 if(found)
4360 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4362 break;
4364 case SPELLFAMILY_PALADIN:
4366 // Seal of Command - receive benefit from Spell Damage and Healing
4367 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4369 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4370 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4372 break;
4374 case SPELLFAMILY_SHAMAN:
4376 // Skyshatter Harness item set bonus
4377 // Stormstrike
4378 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4380 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4381 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4383 // Stormstrike AP Buff
4384 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4386 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4387 break;
4394 int32 fixed_bonus = 0;
4395 for (int j = 0; j < 3; j++)
4397 switch(m_spellInfo->Effect[j])
4399 case SPELL_EFFECT_WEAPON_DAMAGE:
4400 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4401 fixed_bonus += CalculateDamage(j,unitTarget);
4402 break;
4403 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4404 fixed_bonus += CalculateDamage(j,unitTarget);
4405 normalized = true;
4406 break;
4407 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4408 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4410 // applied only to prev.effects fixed damage
4411 if(customBonusDamagePercentMod)
4412 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4413 else
4414 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4415 break;
4416 default:
4417 break; // not weapon damage effect, just skip
4421 // non-weapon damage
4422 int32 bonus = spell_bonus + fixed_bonus;
4424 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4425 if(bonus)
4427 UnitMods unitMod;
4428 switch(m_attackType)
4430 default:
4431 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4432 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4433 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4436 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4437 bonus = int32(bonus*weapon_total_pct);
4440 // + weapon damage with applied weapon% dmg to base weapon damage in call
4441 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4443 // total damage
4444 bonus = int32(bonus*totalDamagePercentMod);
4446 // prevent negative damage
4447 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4449 // Add melee damage bonuses (also check for negative)
4450 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4451 m_damage+= eff_damage;
4453 // Hemorrhage
4454 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4456 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4457 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4460 // Mangle (Cat): CP
4461 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4463 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4464 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4467 // take ammo
4468 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4470 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4472 // wands don't have ammo
4473 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4474 return;
4476 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4478 if(pItem->GetMaxStackCount()==1)
4480 // decrease durability for non-stackable throw weapon
4481 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4483 else
4485 // decrease items amount for stackable throw weapon
4486 uint32 count = 1;
4487 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4490 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4491 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4495 void Spell::EffectThreat(uint32 /*i*/)
4497 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4498 return;
4500 if(!unitTarget->CanHaveThreatList())
4501 return;
4503 unitTarget->AddThreat(m_caster, float(damage));
4506 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4508 if(!unitTarget)
4509 return;
4510 if(!unitTarget->isAlive())
4511 return;
4513 uint32 heal = m_caster->GetMaxHealth();
4515 m_healing+=heal;
4518 void Spell::EffectInterruptCast(uint32 /*i*/)
4520 if(!unitTarget)
4521 return;
4522 if(!unitTarget->isAlive())
4523 return;
4525 // TODO: not all spells that used this effect apply cooldown at school spells
4526 // also exist case: apply cooldown to interrupted cast only and to all spells
4527 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4529 if (unitTarget->m_currentSpells[i])
4531 // check if we can interrupt spell
4532 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4534 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4535 unitTarget->InterruptSpell(i,false);
4541 void Spell::EffectSummonObjectWild(uint32 i)
4543 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4545 GameObject* pGameObj = new GameObject;
4547 WorldObject* target = focusObject;
4548 if( !target )
4549 target = m_caster;
4551 float x,y,z;
4552 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4554 x = m_targets.m_destX;
4555 y = m_targets.m_destY;
4556 z = m_targets.m_destZ;
4558 else
4559 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4561 Map *map = target->GetMap();
4563 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4564 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4566 delete pGameObj;
4567 return;
4570 int32 duration = GetSpellDuration(m_spellInfo);
4571 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4572 pGameObj->SetSpellId(m_spellInfo->Id);
4574 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4575 m_caster->AddGameObject(pGameObj);
4576 map->Add(pGameObj);
4578 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4580 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4582 Player *pl = (Player*)m_caster;
4583 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4584 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4586 uint32 team = ALLIANCE;
4588 if(pl->GetTeam() == team)
4589 team = HORDE;
4591 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4596 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4598 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4600 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4601 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4603 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4608 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4610 GameObject* linkedGO = new GameObject;
4611 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4612 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4614 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4615 linkedGO->SetSpellId(m_spellInfo->Id);
4617 m_caster->AddGameObject(linkedGO);
4618 map->Add(linkedGO);
4620 else
4622 delete linkedGO;
4623 linkedGO = NULL;
4624 return;
4629 void Spell::EffectScriptEffect(uint32 effIndex)
4631 // TODO: we must implement hunter pet summon at login there (spell 6962)
4633 switch(m_spellInfo->SpellFamilyName)
4635 case SPELLFAMILY_GENERIC:
4637 switch(m_spellInfo->Id)
4639 // PX-238 Winter Wondervolt TRAP
4640 case 26275:
4642 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4644 // check presence
4645 for(int j = 0; j < 4; ++j)
4646 if(unitTarget->HasAura(spells[j],0))
4647 return;
4649 // select spell
4650 uint32 iTmpSpellId = spells[urand(0,3)];
4652 // cast
4653 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4654 return;
4656 // Bending Shinbone
4657 case 8856:
4659 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4660 return;
4662 uint32 spell_id = 0;
4663 switch(urand(1,5))
4665 case 1: spell_id = 8854; break;
4666 default: spell_id = 8855; break;
4669 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4670 return;
4672 // Brittle Armor - need remove one 24575 Brittle Armor aura
4673 case 24590:
4674 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4675 return;
4676 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4677 case 26465:
4678 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4679 return;
4680 // Orb teleport spells
4681 case 25140:
4682 case 25143:
4683 case 25650:
4684 case 25652:
4685 case 29128:
4686 case 29129:
4687 case 35376:
4688 case 35727:
4690 if(!unitTarget)
4691 return;
4693 uint32 spellid;
4694 switch(m_spellInfo->Id)
4696 case 25140: spellid = 32571; break;
4697 case 25143: spellid = 32572; break;
4698 case 25650: spellid = 30140; break;
4699 case 25652: spellid = 30141; break;
4700 case 29128: spellid = 32568; break;
4701 case 29129: spellid = 32569; break;
4702 case 35376: spellid = 25649; break;
4703 case 35727: spellid = 35730; break;
4704 default:
4705 return;
4708 unitTarget->CastSpell(unitTarget,spellid,false);
4709 return;
4711 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4712 case 22539:
4713 case 22972:
4714 case 22975:
4715 case 22976:
4716 case 22977:
4717 case 22978:
4718 case 22979:
4719 case 22980:
4720 case 22981:
4721 case 22982:
4722 case 22983:
4723 case 22984:
4724 case 22985:
4726 if(!unitTarget || !unitTarget->isAlive())
4727 return;
4729 // Onyxia Scale Cloak
4730 if(unitTarget->GetDummyAura(22683))
4731 return;
4733 // Shadow Flame
4734 m_caster->CastSpell(unitTarget, 22682, true);
4735 return;
4737 // Summon Black Qiraji Battle Tank
4738 case 26656:
4740 if(!unitTarget)
4741 return;
4743 // Prevent stacking of mounts
4744 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4746 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4747 if (unitTarget->GetAreaId() == 3428)
4748 unitTarget->CastSpell(unitTarget, 25863, false);
4749 else
4750 unitTarget->CastSpell(unitTarget, 26655, false);
4751 break;
4753 // Piccolo of the Flaming Fire
4754 case 17512:
4756 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4757 return;
4758 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4759 break;
4761 // Mirren's Drinking Hat
4762 case 29830:
4764 uint32 item = 0;
4765 switch ( urand(1,6) )
4767 case 1:case 2:case 3:
4768 item = 23584;break; // Loch Modan Lager
4769 case 4:case 5:
4770 item = 23585;break; // Stouthammer Lite
4771 case 6:
4772 item = 23586;break; // Aerie Peak Pale Ale
4774 if (item)
4775 DoCreateItem(effIndex,item);
4776 break;
4778 // Improved Sprint
4779 case 30918:
4781 // Removes snares and roots.
4782 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4783 Unit::AuraMap& Auras = unitTarget->GetAuras();
4784 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4786 next = iter;
4787 ++next;
4788 Aura *aur = iter->second;
4789 if (!aur->IsPositive()) //only remove negative spells
4791 // check for mechanic mask
4792 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4794 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4795 if(Auras.empty())
4796 break;
4797 else
4798 next = Auras.begin();
4802 break;
4804 // Flame Crash
4805 case 41126:
4807 if(!unitTarget)
4808 return;
4810 unitTarget->CastSpell(unitTarget, 41131, true);
4811 break;
4813 // Force Cast - Portal Effect: Sunwell Isle
4814 case 44876:
4816 if(!unitTarget)
4817 return;
4819 unitTarget->CastSpell(unitTarget, 44870, true);
4820 break;
4822 // Goblin Weather Machine
4823 case 46203:
4825 if(!unitTarget)
4826 return;
4828 uint32 spellId;
4829 switch(rand()%4)
4831 case 0: spellId = 46740; break;
4832 case 1: spellId = 46739; break;
4833 case 2: spellId = 46738; break;
4834 case 3: spellId = 46736; break;
4836 unitTarget->CastSpell(unitTarget, spellId, true);
4837 break;
4839 //5,000 Gold
4840 case 46642:
4842 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4843 return;
4845 ((Player*)unitTarget)->ModifyMoney(50000000);
4847 break;
4849 // Emblazon Runeblade
4850 case 51770:
4852 if(!unitTarget)
4853 return;
4855 unitTarget->CastSpell(unitTarget,51771,false);
4856 break;
4858 // Death Gate
4859 case 52751:
4861 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4862 return;
4863 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4864 unitTarget->CastSpell(unitTarget, damage, false);
4865 break;
4867 // random spell learn instead placeholder
4868 case 60893: // Northrend Alchemy Research
4869 case 61177: // Northrend Inscription Research
4870 case 61288: // Minor Inscription Research
4871 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4873 if(!IsExplicitDiscoverySpell(m_spellInfo))
4875 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4876 return;
4879 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4880 return;
4881 Player* player = (Player*)m_caster;
4883 // need replace effect 0 item by loot
4884 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4886 if(!player->HasItemCount(reagent_id,1))
4887 return;
4889 // remove reagent
4890 uint32 count = 1;
4891 player->DestroyItemCount (reagent_id,count,true);
4893 // create some random items
4894 player->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
4896 // learn random explicit discovery recipe (if any)
4897 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4898 player->learnSpell(discoveredSpell,false);
4899 return;
4902 break;
4904 case SPELLFAMILY_WARLOCK:
4906 switch(m_spellInfo->Id)
4908 // Healthstone creating spells
4909 case 6201:
4910 case 6202:
4911 case 5699:
4912 case 11729:
4913 case 11730:
4914 case 27230:
4915 case 47871:
4916 case 47878:
4918 uint32 itemtype;
4919 uint32 rank = 0;
4920 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4921 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4923 if((*i)->GetId() == 18692)
4925 rank = 1;
4926 break;
4928 else if((*i)->GetId() == 18693)
4930 rank = 2;
4931 break;
4935 static uint32 const itypes[8][3] = {
4936 { 5512,19004,19005}, // Minor Healthstone
4937 { 5511,19006,19007}, // Lesser Healthstone
4938 { 5509,19008,19009}, // Healthstone
4939 { 5510,19010,19011}, // Greater Healthstone
4940 { 9421,19012,19013}, // Major Healthstone
4941 {22103,22104,22105}, // Master Healthstone
4942 {36889,36890,36891}, // Demonic Healthstone
4943 {36892,36893,36894} // Fel Healthstone
4946 switch(m_spellInfo->Id)
4948 case 6201:
4949 itemtype=itypes[0][rank];break; // Minor Healthstone
4950 case 6202:
4951 itemtype=itypes[1][rank];break; // Lesser Healthstone
4952 case 5699:
4953 itemtype=itypes[2][rank];break; // Healthstone
4954 case 11729:
4955 itemtype=itypes[3][rank];break; // Greater Healthstone
4956 case 11730:
4957 itemtype=itypes[4][rank];break; // Major Healthstone
4958 case 27230:
4959 itemtype=itypes[5][rank];break; // Master Healthstone
4960 case 47871:
4961 itemtype=itypes[6][rank];break; // Demonic Healthstone
4962 case 47878:
4963 itemtype=itypes[7][rank];break; // Fel Healthstone
4964 default:
4965 return;
4967 DoCreateItem( effIndex, itemtype );
4968 return;
4971 break;
4973 case SPELLFAMILY_PRIEST:
4975 switch(m_spellInfo->Id)
4977 // Pain and Suffering
4978 case 47948:
4980 if (!unitTarget)
4981 return;
4982 // Refresh Shadow Word: Pain on target
4983 Unit::AuraMap& auras = unitTarget->GetAuras();
4984 for(Unit::AuraMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
4986 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4987 if( spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST &&
4988 spellInfo->SpellFamilyFlags & 0x0000000000008000LL &&
4989 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4991 (*itr).second->RefreshAura();
4992 return;
4995 return;
4997 default:
4998 break;
5000 break;
5002 case SPELLFAMILY_HUNTER:
5004 switch(m_spellInfo->Id)
5006 // Chimera Shot
5007 case 53209:
5009 uint32 spellId = 0;
5010 int32 basePoint = 0;
5011 Unit::AuraMap& Auras = unitTarget->GetAuras();
5012 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
5014 Aura *aura = (*i).second;
5015 if (aura->GetCasterGUID() != m_caster->GetGUID())
5016 continue;
5017 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
5018 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
5019 if (!(familyFlag & 0x000000800000C000LL))
5020 continue;
5021 // Refresh aura duration
5022 aura->RefreshAura();
5024 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
5025 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
5027 spellId = 53353; // 53353 Chimera Shot - Serpent
5028 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
5030 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
5031 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
5033 spellId = 53358; // 53358 Chimera Shot - Viper
5034 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
5036 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
5037 if (familyFlag & 0x0000000000008000LL)
5038 spellId = 53359; // 53359 Chimera Shot - Scorpid
5039 // ?? nothing say in spell desc (possibly need addition check)
5040 //if (familyFlag & 0x0000010000000000LL || // dot
5041 // familyFlag & 0x0000100000000000LL) // stun
5043 // spellId = 53366; // 53366 Chimera Shot - Wyvern
5046 if (spellId)
5047 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
5048 return;
5050 default:
5051 break;
5053 break;
5055 case SPELLFAMILY_PALADIN:
5057 // Judgement
5058 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5060 if(!unitTarget || !unitTarget->isAlive())
5061 return;
5062 uint32 spellId1 = 0;
5063 uint32 spellId2 = 0;
5065 // Judgement self add switch
5066 switch (m_spellInfo->Id)
5068 case 41467: break; // Judgement
5069 case 53407: spellId1 = 20184; break; // Judgement of Justice
5070 case 20271: // Judgement of Light
5071 case 57774: spellId1 = 20185; break; // Judgement of Light
5072 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5073 default:
5074 return;
5076 // all seals have aura dummy in 2 effect
5077 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5078 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5080 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5081 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5082 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5083 continue;
5084 spellId2 = (*itr)->GetModifier()->m_amount;
5085 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5086 if (!judge)
5087 continue;
5088 break;
5090 if (spellId1)
5091 m_caster->CastSpell(unitTarget, spellId1, true);
5092 if (spellId2)
5093 m_caster->CastSpell(unitTarget, spellId2, true);
5094 return;
5097 case SPELLFAMILY_POTION:
5099 switch(m_spellInfo->Id)
5101 // Dreaming Glory
5102 case 28698:
5104 if(!unitTarget)
5105 return;
5106 unitTarget->CastSpell(unitTarget, 28694, true);
5107 break;
5109 // Netherbloom
5110 case 28702:
5112 if(!unitTarget)
5113 return;
5114 // 25% chance of casting a random buff
5115 if(roll_chance_i(75))
5116 return;
5118 // triggered spells are 28703 to 28707
5119 // Note: some sources say, that there was the possibility of
5120 // receiving a debuff. However, this seems to be removed by a patch.
5121 const uint32 spellid = 28703;
5123 // don't overwrite an existing aura
5124 for(uint8 i=0; i<5; i++)
5125 if(unitTarget->HasAura(spellid+i, 0))
5126 return;
5127 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5128 break;
5131 // Nightmare Vine
5132 case 28720:
5134 if(!unitTarget)
5135 return;
5136 // 25% chance of casting Nightmare Pollen
5137 if(roll_chance_i(75))
5138 return;
5139 unitTarget->CastSpell(unitTarget, 28721, true);
5140 break;
5143 break;
5147 // normal DB scripted effect
5148 if(!unitTarget)
5149 return;
5151 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5152 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5155 void Spell::EffectSanctuary(uint32 /*i*/)
5157 if(!unitTarget)
5158 return;
5159 //unitTarget->CombatStop();
5161 unitTarget->CombatStop();
5162 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5163 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5164 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5166 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5170 void Spell::EffectAddComboPoints(uint32 /*i*/)
5172 if(!unitTarget)
5173 return;
5175 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5176 return;
5178 if(damage <= 0)
5179 return;
5181 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5184 void Spell::EffectDuel(uint32 i)
5186 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5187 return;
5189 Player *caster = (Player*)m_caster;
5190 Player *target = (Player*)unitTarget;
5192 // caster or target already have requested duel
5193 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5194 return;
5196 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5197 // Don't have to check the target's map since you cannot challenge someone across maps
5198 uint32 mapid = caster->GetMapId();
5199 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5201 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5202 return;
5205 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5206 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5208 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5209 return;
5212 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5213 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5215 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5216 return;
5219 //CREATE DUEL FLAG OBJECT
5220 GameObject* pGameObj = new GameObject;
5222 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5224 Map *map = m_caster->GetMap();
5225 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
5226 map, m_caster->GetPhaseMask(),
5227 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5228 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5229 m_caster->GetPositionZ(),
5230 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5232 delete pGameObj;
5233 return;
5236 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5237 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5238 int32 duration = GetSpellDuration(m_spellInfo);
5239 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5240 pGameObj->SetSpellId(m_spellInfo->Id);
5242 m_caster->AddGameObject(pGameObj);
5243 map->Add(pGameObj);
5244 //END
5246 // Send request
5247 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5248 data << pGameObj->GetGUID();
5249 data << caster->GetGUID();
5250 caster->GetSession()->SendPacket(&data);
5251 target->GetSession()->SendPacket(&data);
5253 // create duel-info
5254 DuelInfo *duel = new DuelInfo;
5255 duel->initiator = caster;
5256 duel->opponent = target;
5257 duel->startTime = 0;
5258 duel->startTimer = 0;
5259 caster->duel = duel;
5261 DuelInfo *duel2 = new DuelInfo;
5262 duel2->initiator = caster;
5263 duel2->opponent = caster;
5264 duel2->startTime = 0;
5265 duel2->startTimer = 0;
5266 target->duel = duel2;
5268 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5269 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5272 void Spell::EffectStuck(uint32 /*i*/)
5274 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5275 return;
5277 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5278 return;
5280 Player* pTarget = (Player*)unitTarget;
5282 sLog.outDebug("Spell Effect: Stuck");
5283 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());
5285 if(pTarget->isInFlight())
5286 return;
5288 // homebind location is loaded always
5289 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5291 // Stuck spell trigger Hearthstone cooldown
5292 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5293 if(!spellInfo)
5294 return;
5295 Spell spell(pTarget,spellInfo,true,0);
5296 spell.SendSpellCooldown();
5299 void Spell::EffectSummonPlayer(uint32 /*i*/)
5301 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5302 return;
5304 // Evil Twin (ignore player summon, but hide this for summoner)
5305 if(unitTarget->GetDummyAura(23445))
5306 return;
5308 float x,y,z;
5309 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5311 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5313 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5314 data << uint64(m_caster->GetGUID()); // summoner guid
5315 data << uint32(m_caster->GetZoneId()); // summoner zone
5316 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5317 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5320 static ScriptInfo generateActivateCommand()
5322 ScriptInfo si;
5323 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5324 return si;
5327 void Spell::EffectActivateObject(uint32 effect_idx)
5329 if(!gameObjTarget)
5330 return;
5332 static ScriptInfo activateCommand = generateActivateCommand();
5334 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5336 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5339 void Spell::EffectApplyGlyph(uint32 i)
5341 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5342 return;
5344 Player *player = (Player*)m_caster;
5346 // remove old glyph
5347 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5349 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5351 player->RemoveAurasDueToSpell(old_gp->SpellId);
5352 player->SetGlyph(m_glyphIndex, 0);
5356 // apply new one
5357 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5359 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5361 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5363 if(gp->TypeFlags != gs->TypeFlags)
5365 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5366 return; // glyph slot missmatch
5370 player->CastSpell(m_caster, gp->SpellId, true);
5371 player->SetGlyph(m_glyphIndex, glyph);
5376 void Spell::EffectSummonTotem(uint32 i)
5378 uint8 slot = 0;
5379 switch(m_spellInfo->EffectMiscValueB[i])
5381 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5382 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5383 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5384 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5385 // Battle standard case
5386 case SUMMON_TYPE_TOTEM: slot = 254; break;
5387 // jewelery statue case, like totem without slot
5388 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5389 default: return;
5392 if(slot < MAX_TOTEM)
5394 uint64 guid = m_caster->m_TotemSlot[slot];
5395 if(guid != 0)
5397 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5398 if(OldTotem && OldTotem->isTotem())
5399 ((Totem*)OldTotem)->UnSummon();
5403 uint32 team = 0;
5404 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5405 team = ((Player*)m_caster)->GetTeam();
5407 Totem* pTotem = new Totem;
5409 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
5410 m_spellInfo->EffectMiscValue[i], team ))
5412 delete pTotem;
5413 return;
5416 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5418 float x,y,z;
5419 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5421 // totem must be at same Z in case swimming caster and etc.
5422 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5423 z = m_caster->GetPositionZ();
5425 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5427 if(slot < MAX_TOTEM)
5428 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5430 pTotem->SetOwner(m_caster->GetGUID());
5431 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5433 int32 duration=GetSpellDuration(m_spellInfo);
5434 if(Player* modOwner = m_caster->GetSpellModOwner())
5435 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5436 pTotem->SetDuration(duration);
5438 if (damage) // if not spell info, DB values used
5440 pTotem->SetMaxHealth(damage);
5441 pTotem->SetHealth(damage);
5444 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5446 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5447 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5449 pTotem->Summon(m_caster);
5451 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5453 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5454 data << uint8(slot);
5455 data << uint64(pTotem->GetGUID());
5456 data << uint32(duration);
5457 data << uint32(m_spellInfo->Id);
5458 ((Player*)m_caster)->SendDirectMessage(&data);
5462 void Spell::EffectEnchantHeldItem(uint32 i)
5464 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5465 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5466 return;
5468 Player* item_owner = (Player*)unitTarget;
5469 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5471 if(!item )
5472 return;
5474 // must be equipped
5475 if(!item ->IsEquipped())
5476 return;
5478 if (m_spellInfo->EffectMiscValue[i])
5480 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5481 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5482 if(!duration)
5483 duration = m_currentBasePoints[i]+1; //Base points after ..
5484 if(!duration)
5485 duration = 10; //10 seconds for enchants which don't have listed duration
5487 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5488 if(!pEnchant)
5489 return;
5491 // Always go to temp enchantment slot
5492 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5494 // Enchantment will not be applied if a different one already exists
5495 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5496 return;
5498 // Apply the temporary enchantment
5499 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5500 item_owner->ApplyEnchantment(item,slot,true);
5504 void Spell::EffectDisEnchant(uint32 /*i*/)
5506 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5507 return;
5509 Player* p_caster = (Player*)m_caster;
5510 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5511 return;
5513 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5515 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5517 // item will be removed at disenchanting end
5520 void Spell::EffectInebriate(uint32 /*i*/)
5522 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5523 return;
5525 Player *player = (Player*)unitTarget;
5526 uint16 currentDrunk = player->GetDrunkValue();
5527 uint16 drunkMod = damage * 256;
5528 if (currentDrunk + drunkMod > 0xFFFF)
5529 currentDrunk = 0xFFFF;
5530 else
5531 currentDrunk += drunkMod;
5532 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5535 void Spell::EffectFeedPet(uint32 i)
5537 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5538 return;
5540 Player *_player = (Player*)m_caster;
5542 Item* foodItem = m_targets.getItemTarget();
5543 if(!foodItem)
5544 return;
5546 Pet *pet = _player->GetPet();
5547 if(!pet)
5548 return;
5550 if(!pet->isAlive())
5551 return;
5553 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5554 if(benefit <= 0)
5555 return;
5557 uint32 count = 1;
5558 _player->DestroyItemCount(foodItem,count,true);
5559 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5561 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5564 void Spell::EffectDismissPet(uint32 /*i*/)
5566 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5567 return;
5569 Pet* pet = m_caster->GetPet();
5571 // not let dismiss dead pet
5572 if(!pet||!pet->isAlive())
5573 return;
5575 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5578 void Spell::EffectSummonObject(uint32 i)
5580 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5582 uint8 slot = 0;
5583 switch(m_spellInfo->Effect[i])
5585 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5586 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5587 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5588 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5589 default: return;
5592 uint64 guid = m_caster->m_ObjectSlot[slot];
5593 if(guid != 0)
5595 GameObject* obj = NULL;
5596 if( m_caster )
5597 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5599 if(obj) obj->Delete();
5600 m_caster->m_ObjectSlot[slot] = 0;
5603 GameObject* pGameObj = new GameObject;
5605 float rot2 = sin(m_caster->GetOrientation()/2);
5606 float rot3 = cos(m_caster->GetOrientation()/2);
5608 float x,y,z;
5609 // If dest location if present
5610 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5612 x = m_targets.m_destX;
5613 y = m_targets.m_destY;
5614 z = m_targets.m_destZ;
5616 // Summon in random point all other units if location present
5617 else
5618 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5620 Map *map = m_caster->GetMap();
5621 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
5622 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5624 delete pGameObj;
5625 return;
5628 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5629 int32 duration = GetSpellDuration(m_spellInfo);
5630 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5631 pGameObj->SetSpellId(m_spellInfo->Id);
5632 m_caster->AddGameObject(pGameObj);
5634 map->Add(pGameObj);
5635 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5636 data << pGameObj->GetGUID();
5637 m_caster->SendMessageToSet(&data,true);
5639 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5642 void Spell::EffectResurrect(uint32 /*effIndex*/)
5644 if(!unitTarget)
5645 return;
5646 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5647 return;
5649 if(unitTarget->isAlive())
5650 return;
5651 if(!unitTarget->IsInWorld())
5652 return;
5654 switch (m_spellInfo->Id)
5656 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5657 case 8342:
5658 if (roll_chance_i(67))
5660 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5661 return;
5663 break;
5664 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5665 case 22999:
5666 if (roll_chance_i(50))
5668 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5669 return;
5671 break;
5672 default:
5673 break;
5676 Player* pTarget = ((Player*)unitTarget);
5678 if(pTarget->isRessurectRequested()) // already have one active request
5679 return;
5681 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5682 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5684 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5685 SendResurrectRequest(pTarget);
5688 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5690 if(!unitTarget || !unitTarget->isAlive())
5691 return;
5693 if( unitTarget->m_extraAttacks )
5694 return;
5696 unitTarget->m_extraAttacks = damage;
5699 void Spell::EffectParry(uint32 /*i*/)
5701 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5702 ((Player*)unitTarget)->SetCanParry(true);
5705 void Spell::EffectBlock(uint32 /*i*/)
5707 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5708 ((Player*)unitTarget)->SetCanBlock(true);
5711 void Spell::EffectMomentMove(uint32 i)
5713 if(unitTarget->isInFlight())
5714 return;
5716 if( m_spellInfo->rangeIndex== 1) //self range
5718 uint32 mapid = m_caster->GetMapId();
5719 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5721 // before caster
5722 float fx,fy,fz;
5723 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5724 float ox,oy,oz;
5725 unitTarget->GetPosition(ox,oy,oz);
5727 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5728 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5730 fx = fx2;
5731 fy = fy2;
5732 fz = fz2;
5733 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5736 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5737 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5738 else
5739 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5743 void Spell::EffectReputation(uint32 i)
5745 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5746 return;
5748 Player *_player = (Player*)unitTarget;
5750 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5752 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5754 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5756 if(!factionEntry)
5757 return;
5759 _player->ModifyFactionReputation(factionEntry,rep_change);
5762 void Spell::EffectQuestComplete(uint32 i)
5764 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5765 return;
5767 Player *_player = (Player*)m_caster;
5769 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5770 _player->AreaExploredOrEventHappens(quest_id);
5773 void Spell::EffectSelfResurrect(uint32 i)
5775 if(!unitTarget || unitTarget->isAlive())
5776 return;
5777 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5778 return;
5779 if(!unitTarget->IsInWorld())
5780 return;
5782 uint32 health = 0;
5783 uint32 mana = 0;
5785 // flat case
5786 if(damage < 0)
5788 health = uint32(-damage);
5789 mana = m_spellInfo->EffectMiscValue[i];
5791 // percent case
5792 else
5794 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5795 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5796 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5799 Player *plr = ((Player*)unitTarget);
5800 plr->ResurrectPlayer(0.0f);
5802 plr->SetHealth( health );
5803 plr->SetPower(POWER_MANA, mana );
5804 plr->SetPower(POWER_RAGE, 0 );
5805 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5807 plr->SpawnCorpseBones();
5809 plr->SaveToDB();
5812 void Spell::EffectSkinning(uint32 /*i*/)
5814 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5815 return;
5816 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5817 return;
5819 Creature* creature = (Creature*) unitTarget;
5820 int32 targetLevel = creature->getLevel();
5822 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5824 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5825 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5827 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5829 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5831 // Double chances for elites
5832 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5835 void Spell::EffectCharge(uint32 /*i*/)
5837 if(!unitTarget || !m_caster)
5838 return;
5840 float x, y, z;
5841 unitTarget->GetContactPoint(m_caster, x, y, z);
5842 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5843 ((Creature *)unitTarget)->StopMoving();
5845 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5846 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5848 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5849 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5851 // not all charge effects used in negative spells
5852 if ( !IsPositiveSpell(m_spellInfo->Id))
5853 m_caster->Attack(unitTarget,true);
5856 void Spell::EffectSummonCritter(uint32 i)
5858 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5859 return;
5860 Player* player = (Player*)m_caster;
5862 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5863 if(!pet_entry)
5864 return;
5866 Pet* old_critter = player->GetMiniPet();
5868 // for same pet just despawn
5869 if(old_critter && old_critter->GetEntry() == pet_entry)
5871 player->RemoveMiniPet();
5872 return;
5875 // despawn old pet before summon new
5876 if(old_critter)
5877 player->RemoveMiniPet();
5879 // summon new pet
5880 Pet* critter = new Pet(MINI_PET);
5882 Map *map = m_caster->GetMap();
5883 uint32 pet_number = objmgr.GeneratePetNumber();
5884 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
5885 pet_entry, pet_number))
5887 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5888 delete critter;
5889 return;
5892 float x,y,z;
5893 // If dest location if present
5894 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5896 x = m_targets.m_destX;
5897 y = m_targets.m_destY;
5898 z = m_targets.m_destZ;
5900 // Summon if dest location not present near caster
5901 else
5902 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5904 critter->Relocate(x,y,z,m_caster->GetOrientation());
5906 if(!critter->IsPositionValid())
5908 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5909 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5910 delete critter;
5911 return;
5914 critter->SetOwnerGUID(m_caster->GetGUID());
5915 critter->SetCreatorGUID(m_caster->GetGUID());
5916 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5917 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5919 critter->AIM_Initialize();
5920 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5921 critter->SetMaxHealth(1);
5922 critter->SetHealth(1);
5923 critter->SetLevel(1);
5925 // set timer for unsummon
5926 int32 duration = GetSpellDuration(m_spellInfo);
5927 if(duration > 0)
5928 critter->SetDuration(duration);
5930 std::string name = player->GetName();
5931 name.append(petTypeSuffix[critter->getPetType()]);
5932 critter->SetName( name );
5933 player->SetMiniPet(critter);
5935 map->Add((Creature*)critter);
5938 void Spell::EffectKnockBack(uint32 i)
5940 if(!unitTarget || !m_caster)
5941 return;
5943 // Effect only works on players
5944 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5945 return;
5947 float vsin = sin(m_caster->GetAngle(unitTarget));
5948 float vcos = cos(m_caster->GetAngle(unitTarget));
5950 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5951 data.append(unitTarget->GetPackGUID());
5952 data << uint32(0); // Sequence
5953 data << float(vcos); // x direction
5954 data << float(vsin); // y direction
5955 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5956 data << float(damage/-10); // Z Movement speed (vertical)
5958 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5961 void Spell::EffectSendTaxi(uint32 i)
5963 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5964 return;
5966 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5967 if(!entry)
5968 return;
5970 std::vector<uint32> nodes;
5972 nodes.resize(2);
5973 nodes[0] = entry->from;
5974 nodes[1] = entry->to;
5976 uint32 mountid = 0;
5977 switch(m_spellInfo->Id)
5979 case 31606: //Stormcrow Amulet
5980 mountid = 17447;
5981 break;
5982 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5983 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5984 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5985 mountid = 22840;
5986 break;
5987 case 34905: //Stealth Flight
5988 mountid = 6851;
5989 break;
5990 case 45883: //Amber Ledge to Beryl Point
5991 mountid = 23524;
5992 break;
5993 case 46064: //Amber Ledge to Coldarra
5994 mountid = 6371;
5995 break;
5996 case 53335: //Stormwind Harbor Flight - Peaceful
5997 mountid = 6852;
5998 break;
6001 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
6005 void Spell::EffectPlayerPull(uint32 i)
6007 if(!unitTarget || !m_caster)
6008 return;
6010 // Effect only works on players
6011 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6012 return;
6014 float vsin = sin(unitTarget->GetAngle(m_caster));
6015 float vcos = cos(unitTarget->GetAngle(m_caster));
6017 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6018 data.append(unitTarget->GetPackGUID());
6019 data << uint32(0); // Sequence
6020 data << float(vcos); // x direction
6021 data << float(vsin); // y direction
6022 // Horizontal speed
6023 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
6024 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
6026 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6029 void Spell::EffectDispelMechanic(uint32 i)
6031 if(!unitTarget)
6032 return;
6034 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
6036 Unit::AuraMap& Auras = unitTarget->GetAuras();
6037 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
6039 next = iter;
6040 ++next;
6041 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
6042 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
6044 unitTarget->RemoveAurasDueToSpell(spell->Id);
6045 if(Auras.empty())
6046 break;
6047 else
6048 next = Auras.begin();
6051 return;
6054 void Spell::EffectSummonDeadPet(uint32 /*i*/)
6056 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6057 return;
6058 Player *_player = (Player*)m_caster;
6059 Pet *pet = _player->GetPet();
6060 if(!pet)
6061 return;
6062 if(pet->isAlive())
6063 return;
6064 if(damage < 0)
6065 return;
6066 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6067 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6068 pet->setDeathState( ALIVE );
6069 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6070 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6072 pet->AIM_Initialize();
6074 _player->PetSpellInitialize();
6075 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6078 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6080 float mana = 0;
6081 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6083 if(!m_caster->m_TotemSlot[slot])
6084 continue;
6086 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
6087 if(totem && totem->isTotem())
6089 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6090 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6091 if(spellInfo)
6092 mana += spellInfo->manaCost * damage / 100;
6093 ((Totem*)totem)->UnSummon();
6097 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
6098 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
6101 void Spell::EffectDurabilityDamage(uint32 i)
6103 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6104 return;
6106 int32 slot = m_spellInfo->EffectMiscValue[i];
6108 // FIXME: some spells effects have value -1/-2
6109 // Possibly its mean -1 all player equipped items and -2 all items
6110 if(slot < 0)
6112 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6113 return;
6116 // invalid slot value
6117 if(slot >= INVENTORY_SLOT_BAG_END)
6118 return;
6120 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6121 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6124 void Spell::EffectDurabilityDamagePCT(uint32 i)
6126 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6127 return;
6129 int32 slot = m_spellInfo->EffectMiscValue[i];
6131 // FIXME: some spells effects have value -1/-2
6132 // Possibly its mean -1 all player equipped items and -2 all items
6133 if(slot < 0)
6135 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6136 return;
6139 // invalid slot value
6140 if(slot >= INVENTORY_SLOT_BAG_END)
6141 return;
6143 if(damage <= 0)
6144 return;
6146 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6147 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6150 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6152 if(!unitTarget)
6153 return;
6155 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6158 void Spell::EffectTransmitted(uint32 effIndex)
6160 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6162 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6164 if (!goinfo)
6166 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6167 return;
6170 float fx,fy,fz;
6172 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6174 fx = m_targets.m_destX;
6175 fy = m_targets.m_destY;
6176 fz = m_targets.m_destZ;
6178 //FIXME: this can be better check for most objects but still hack
6179 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6181 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6182 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6184 else
6186 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6187 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6188 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6190 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6193 Map *cMap = m_caster->GetMap();
6195 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6197 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6198 { // but this is not proper, we really need to ignore not materialized objects
6199 SendCastResult(SPELL_FAILED_NOT_HERE);
6200 SendChannelUpdate(0);
6201 return;
6204 // replace by water level in this case
6205 fz = cMap->GetWaterLevel(fx,fy);
6207 // if gameobject is summoning object, it should be spawned right on caster's position
6208 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6210 m_caster->GetPosition(fx,fy,fz);
6213 GameObject* pGameObj = new GameObject;
6215 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6216 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6218 delete pGameObj;
6219 return;
6222 int32 duration = GetSpellDuration(m_spellInfo);
6224 switch(goinfo->type)
6226 case GAMEOBJECT_TYPE_FISHINGNODE:
6228 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6229 // Orientation3
6230 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6231 // Orientation4
6232 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6233 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6235 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6236 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6237 int32 lastSec;
6238 switch(urand(0, 3))
6240 case 0: lastSec = 3; break;
6241 case 1: lastSec = 7; break;
6242 case 2: lastSec = 13; break;
6243 case 3: lastSec = 17; break;
6246 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6247 break;
6249 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6251 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6253 pGameObj->AddUniqueUse((Player*)m_caster);
6254 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6256 break;
6258 case GAMEOBJECT_TYPE_FISHINGHOLE:
6259 case GAMEOBJECT_TYPE_CHEST:
6260 default:
6262 break;
6266 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6268 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6270 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6271 pGameObj->SetSpellId(m_spellInfo->Id);
6273 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6274 //m_caster->AddGameObject(pGameObj);
6275 //m_ObjToDel.push_back(pGameObj);
6277 cMap->Add(pGameObj);
6279 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6280 data << uint64(pGameObj->GetGUID());
6281 m_caster->SendMessageToSet(&data,true);
6283 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6285 GameObject* linkedGO = new GameObject;
6286 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6287 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6289 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6290 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6291 linkedGO->SetSpellId(m_spellInfo->Id);
6292 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6294 linkedGO->GetMap()->Add(linkedGO);
6296 else
6298 delete linkedGO;
6299 linkedGO = NULL;
6300 return;
6305 void Spell::EffectProspecting(uint32 /*i*/)
6307 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6308 return;
6310 Player* p_caster = (Player*)m_caster;
6311 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6312 return;
6314 if(itemTarget->GetCount() < 5)
6315 return;
6317 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6319 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6320 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6321 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6324 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6327 void Spell::EffectMilling(uint32 /*i*/)
6329 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6330 return;
6332 Player* p_caster = (Player*)m_caster;
6333 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6334 return;
6336 if(itemTarget->GetCount() < 5)
6337 return;
6339 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6341 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6342 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6343 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6346 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6349 void Spell::EffectSkill(uint32 /*i*/)
6351 sLog.outDebug("WORLD: SkillEFFECT");
6354 void Spell::EffectSummonDemon(uint32 i)
6356 float px = m_targets.m_destX;
6357 float py = m_targets.m_destY;
6358 float pz = m_targets.m_destZ;
6360 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6361 if (!Charmed)
6362 return;
6364 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6365 Charmed->SetLevel(m_caster->getLevel());
6367 // TODO: Add damage/mana/hp according to level
6369 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6371 // Enslave demon effect, without mana cost and cooldown
6372 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6374 // Inferno effect
6375 Charmed->CastSpell(Charmed, 22703, true, 0);
6379 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6380 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6381 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6382 This is why we use a half sec delay between the visual effect and the resurrection itself */
6383 void Spell::EffectSpiritHeal(uint32 /*i*/)
6386 if(!unitTarget || unitTarget->isAlive())
6387 return;
6388 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6389 return;
6390 if(!unitTarget->IsInWorld())
6391 return;
6393 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6394 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6395 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6396 ((Player*)unitTarget)->SpawnCorpseBones();
6400 // remove insignia spell effect
6401 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6403 sLog.outDebug("Effect: SkinPlayerCorpse");
6404 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6405 return;
6407 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6410 void Spell::EffectStealBeneficialBuff(uint32 i)
6412 sLog.outDebug("Effect: StealBeneficialBuff");
6414 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6415 return;
6417 std::vector <Aura *> steal_list;
6418 // Create dispel mask by dispel type
6419 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6420 Unit::AuraMap const& auras = unitTarget->GetAuras();
6421 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6423 Aura *aur = (*itr).second;
6424 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6426 // Need check for passive? this
6427 if (aur->IsPositive() && !aur->IsPassive())
6428 steal_list.push_back(aur);
6431 // Ok if exist some buffs for dispel try dispel it
6432 if (!steal_list.empty())
6434 std::list < std::pair<uint32,uint64> > success_list;
6435 int32 list_size = steal_list.size();
6436 // Dispell N = damage buffs (or while exist buffs for dispel)
6437 for (int32 count=0; count < damage && list_size > 0; ++count)
6439 // Random select buff for dispel
6440 Aura *aur = steal_list[urand(0, list_size-1)];
6441 // Not use chance for steal
6442 // TODO possible need do it
6443 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6445 // Remove buff from list for prevent doubles
6446 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6448 Aura *stealed = *j;
6449 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6451 j = steal_list.erase(j);
6452 --list_size;
6454 else
6455 ++j;
6458 // Really try steal and send log
6459 if (!success_list.empty())
6461 int32 count = success_list.size();
6462 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6463 data.append(unitTarget->GetPackGUID()); // Victim GUID
6464 data.append(m_caster->GetPackGUID()); // Caster GUID
6465 data << uint32(m_spellInfo->Id); // Dispell spell id
6466 data << uint8(0); // not used
6467 data << uint32(count); // count
6468 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6470 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6471 data << uint32(spellInfo->Id); // Spell Id
6472 data << uint8(0); // 0 - steals !=0 transfers
6473 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6475 m_caster->SendMessageToSet(&data, true);
6480 void Spell::EffectKillCredit(uint32 i)
6482 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6483 return;
6485 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6488 void Spell::EffectQuestFail(uint32 i)
6490 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6491 return;
6493 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6496 void Spell::EffectActivateRune(uint32 eff_idx)
6498 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6499 return;
6501 Player *plr = (Player*)m_caster;
6503 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6504 return;
6506 for(uint32 j = 0; j < MAX_RUNES; ++j)
6508 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6510 plr->SetRuneCooldown(j, 0);
6515 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6517 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6518 ((Player*)unitTarget)->SetCanTitanGrip(true);
6521 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6523 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6524 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6525 return;
6527 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);