[7798] More Player::ActivateTaxiPathTo use improvements
[getmangos.git] / src / game / SpellEffects.cpp
blob95ccc7590605948eeecaf93c7fbcbeb5f5fbd526
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Database/DatabaseEnv.h"
21 #include "WorldPacket.h"
22 #include "Opcodes.h"
23 #include "Log.h"
24 #include "UpdateMask.h"
25 #include "World.h"
26 #include "ObjectMgr.h"
27 #include "SpellMgr.h"
28 #include "Player.h"
29 #include "SkillExtraItems.h"
30 #include "Unit.h"
31 #include "Spell.h"
32 #include "DynamicObject.h"
33 #include "SpellAuras.h"
34 #include "Group.h"
35 #include "UpdateData.h"
36 #include "MapManager.h"
37 #include "ObjectAccessor.h"
38 #include "SharedDefines.h"
39 #include "Pet.h"
40 #include "GameObject.h"
41 #include "GossipDef.h"
42 #include "Creature.h"
43 #include "Totem.h"
44 #include "CreatureAI.h"
45 #include "BattleGroundMgr.h"
46 #include "BattleGround.h"
47 #include "BattleGroundEY.h"
48 #include "BattleGroundWS.h"
49 #include "VMapFactory.h"
50 #include "Language.h"
51 #include "SocialMgr.h"
52 #include "Util.h"
53 #include "TemporarySummon.h"
54 #include "ScriptCalls.h"
55 #include "SkillDiscovery.h"
56 #include "Formulas.h"
58 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
60 &Spell::EffectNULL, // 0
61 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectUnused, // 41 SPELL_EFFECT_JUMP
102 &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
103 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
107 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
120 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
126 &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
127 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
134 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
135 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectUnused, // 87 SPELL_EFFECT_WMO_DAMAGE
148 &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
149 &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
150 &Spell::EffectUnused, // 90 SPELL_EFFECT_KILL_CREDIT
151 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
154 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectUnused, // 97 SPELL_EFFECT_97
158 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
170 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectUnused, //112 SPELL_EFFECT_112
173 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
185 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
192 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
193 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
199 &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
200 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
202 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
205 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
206 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
207 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
209 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
210 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
211 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
213 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
214 &Spell::EffectNULL, //154 unused
215 &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
216 &Spell::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
217 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
218 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
219 &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again
222 void Spell::EffectNULL(uint32 /*i*/)
224 sLog.outDebug("WORLD: Spell Effect DUMMY");
227 void Spell::EffectUnused(uint32 /*i*/)
229 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
232 void Spell::EffectResurrectNew(uint32 i)
234 if(!unitTarget || unitTarget->isAlive())
235 return;
237 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
238 return;
240 if(!unitTarget->IsInWorld())
241 return;
243 Player* pTarget = ((Player*)unitTarget);
245 if(pTarget->isRessurectRequested()) // already have one active request
246 return;
248 uint32 health = damage;
249 uint32 mana = m_spellInfo->EffectMiscValue[i];
250 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
251 SendResurrectRequest(pTarget);
254 void Spell::EffectInstaKill(uint32 /*i*/)
256 if( !unitTarget || !unitTarget->isAlive() )
257 return;
259 // Demonic Sacrifice
260 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
262 uint32 entry = unitTarget->GetEntry();
263 uint32 spellID;
264 switch(entry)
266 case 416: spellID=18789; break; //imp
267 case 417: spellID=18792; break; //fellhunter
268 case 1860: spellID=18790; break; //void
269 case 1863: spellID=18791; break; //succubus
270 case 17252: spellID=35701; break; //fellguard
271 default:
272 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
273 return;
276 m_caster->CastSpell(m_caster,spellID,true);
279 if(m_caster==unitTarget) // prevent interrupt message
280 finish();
282 uint32 health = unitTarget->GetHealth();
283 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
286 void Spell::EffectEnvirinmentalDMG(uint32 i)
288 uint32 absorb = 0;
289 uint32 resist = 0;
291 // Note: this hack with damage replace required until GO casting not implemented
292 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
293 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
294 damage = m_spellInfo->CalculateSimpleValue(i);
296 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
298 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
299 if(m_caster->GetTypeId() == TYPEID_PLAYER)
300 ((Player*)m_caster)->EnvironmentalDamage(DAMAGE_FIRE,damage);
303 void Spell::EffectSchoolDMG(uint32 effect_idx)
305 if( unitTarget && unitTarget->isAlive())
307 switch(m_spellInfo->SpellFamilyName)
309 case SPELLFAMILY_GENERIC:
311 //Gore
312 if(m_spellInfo->SpellIconID == 2269 )
314 damage+= rand()%2 ? damage : 0;
317 switch(m_spellInfo->Id) // better way to check unknown
319 // Meteor like spells (divided damage to targets)
320 case 24340: case 26558: case 28884: // Meteor
321 case 36837: case 38903: case 41276: // Meteor
322 case 26789: // Shard of the Fallen Star
323 case 31436: // Malevolent Cleave
324 case 35181: // Dive Bomb
325 case 40810: case 43267: case 43268: // Saber Lash
326 case 42384: // Brutal Swipe
327 case 45150: // Meteor Slash
329 uint32 count = 0;
330 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
331 if(ihit->effectMask & (1<<effect_idx))
332 ++count;
334 damage /= count; // divide to all targets
335 break;
337 // percent from health with min
338 case 25599: // Thundercrash
340 damage = unitTarget->GetHealth() / 2;
341 if(damage < 200)
342 damage = 200;
343 break;
345 // Intercept (warrior spell trigger)
346 case 20253:
347 case 61491:
349 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
350 break;
352 // Cataclysmic Bolt
353 case 38441:
354 damage = unitTarget->GetMaxHealth() / 2;
355 break;
357 break;
360 case SPELLFAMILY_MAGE:
362 // Arcane Blast
363 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
365 m_caster->CastSpell(m_caster,36032,true);
367 break;
369 case SPELLFAMILY_WARRIOR:
371 // Bloodthirst
372 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
374 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
376 // Shield Slam
377 else if(m_spellInfo->SpellFamilyFlags & 0x0000020000000000LL && m_spellInfo->Category==1209)
378 damage += int32(m_caster->GetShieldBlockValue());
379 // Victory Rush
380 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
382 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
383 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
385 // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
386 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000400LL)
387 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
388 // Heroic Throw ${$m1+$AP*.50}
389 else if(m_spellInfo->SpellFamilyFlags & 0x0000000100000000LL)
390 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
391 // Shockwave ${$m3/100*$AP}
392 else if(m_spellInfo->SpellFamilyFlags & 0x0000800000000000LL)
394 int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
395 if (pct > 0)
396 damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
397 break;
399 break;
401 case SPELLFAMILY_WARLOCK:
403 // Incinerate Rank 1 & 2
404 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
406 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
407 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
408 damage += int32(damage*0.25f);
410 break;
412 case SPELLFAMILY_PRIEST:
414 // Shadow Word: Death - deals damage equal to damage done to caster
415 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
416 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
417 break;
419 case SPELLFAMILY_DRUID:
421 // Ferocious Bite
422 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
424 // converts each extra point of energy into ($f1+$AP/410) additional damage
425 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
426 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
427 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
428 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
429 m_caster->SetPower(POWER_ENERGY,0);
431 // Rake
432 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
434 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
436 // Swipe
437 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
439 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
441 //Mangle Bonus for the initial damage of Lacerate and Rake
442 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
443 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
445 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
446 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
447 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
449 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
450 break;
453 break;
455 case SPELLFAMILY_ROGUE:
457 // Envenom
458 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
460 // consume from stack dozes not more that have combo-points
461 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
463 Aura *poison = 0;
464 // Lookup for Deadly poison (only attacker applied)
465 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
466 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
467 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
468 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
469 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
471 poison = *itr;
472 break;
474 // count consumed deadly poison doses at target
475 if (poison)
477 uint32 spellId = poison->GetId();
478 uint32 doses = poison->GetStackAmount();
479 if (doses > combo)
480 doses = combo;
481 for (int i=0; i< doses; i++)
482 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
483 damage *= doses;
484 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
486 // Eviscerate and Envenom Bonus Damage (item set effect)
487 if(m_caster->GetDummyAura(37169))
488 damage += ((Player*)m_caster)->GetComboPoints()*40;
491 // Eviscerate
492 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
494 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
496 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
497 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
499 // Eviscerate and Envenom Bonus Damage (item set effect)
500 if(m_caster->GetDummyAura(37169))
501 damage += combo*40;
504 // Gouge
505 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
507 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.21f);
509 // Instant Poison
510 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
512 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
514 // Wound Poison
515 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
517 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
519 break;
521 case SPELLFAMILY_HUNTER:
523 // Mongoose Bite
524 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
526 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
528 // Counterattack
529 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
531 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
533 // Arcane Shot
534 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
536 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
538 // Steady Shot
539 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
541 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
542 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
544 // Explosive Trap Effect
545 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
547 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
549 break;
551 case SPELLFAMILY_PALADIN:
553 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
554 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
556 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
557 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
558 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
559 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
560 // Get stack of Holy Vengeance on the target added by caster
561 uint32 stacks = 0;
562 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
563 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
564 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
566 stacks = (*itr)->GetStackAmount();
567 break;
569 // + 10% for each application of Holy Vengeance on the target
570 if(stacks)
571 damage += damage * stacks * 10 /100;
573 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
574 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
576 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
577 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
578 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
579 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
581 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
582 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
584 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
585 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
586 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
587 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
589 // Hammer of the Righteous
590 else if(m_spellInfo->SpellFamilyFlags&0x0004000000000000LL)
592 // Add main hand dps * effect[2] amount
593 float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
594 int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
595 damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
597 // Shield of Righteousness
598 else if(m_spellInfo->SpellFamilyFlags&0x0010000000000000LL)
600 damage+=int32(m_caster->GetShieldBlockValue());
602 break;
606 if(damage >= 0)
607 m_damage+= damage;
611 void Spell::EffectDummy(uint32 i)
613 if(!unitTarget && !gameObjTarget && !itemTarget)
614 return;
616 // selection by spell family
617 switch(m_spellInfo->SpellFamilyName)
619 case SPELLFAMILY_GENERIC:
621 switch(m_spellInfo->Id )
623 case 8063: // Deviate Fish
625 if(m_caster->GetTypeId() != TYPEID_PLAYER)
626 return;
628 uint32 spell_id = 0;
629 switch(urand(1,5))
631 case 1: spell_id = 8064; break; // Sleepy
632 case 2: spell_id = 8065; break; // Invigorate
633 case 3: spell_id = 8066; break; // Shrink
634 case 4: spell_id = 8067; break; // Party Time!
635 case 5: spell_id = 8068; break; // Healthy Spirit
637 m_caster->CastSpell(m_caster,spell_id,true,NULL);
638 return;
640 case 8213: // Savory Deviate Delight
642 if(m_caster->GetTypeId() != TYPEID_PLAYER)
643 return;
645 uint32 spell_id = 0;
646 switch(urand(1,2))
648 // Flip Out - ninja
649 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
650 // Yaaarrrr - pirate
651 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
653 m_caster->CastSpell(m_caster,spell_id,true,NULL);
654 return;
656 case 8593: // Symbol of life (restore creature to life)
657 case 31225: // Shimmering Vessel (restore creature to life)
659 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
660 return;
661 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
662 return;
664 case 12162: // Deep wounds
665 case 12850: // (now good common check for this spells)
666 case 12868:
668 if(!unitTarget)
669 return;
671 float damage;
672 // DW should benefit of attack power, damage percent mods etc.
673 // TODO: check if using offhand damage is correct and if it should be divided by 2
674 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
675 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
676 else
677 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
679 switch (m_spellInfo->Id)
681 case 12850: damage *= 0.2f; break;
682 case 12162: damage *= 0.4f; break;
683 case 12868: damage *= 0.6f; break;
684 default:
685 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
686 return;
689 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
690 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
691 return;
693 case 13120: // net-o-matic
695 if(!unitTarget)
696 return;
698 uint32 spell_id = 0;
700 uint32 roll = urand(0, 99);
702 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
703 spell_id = 16566;
704 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
705 spell_id = 13119;
706 else // normal root
707 spell_id = 13099;
709 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
710 return;
712 case 13567: // Dummy Trigger
714 // can be used for different aura triggering, so select by aura
715 if(!m_triggeredByAuraSpell || !unitTarget)
716 return;
718 switch(m_triggeredByAuraSpell->Id)
720 case 26467: // Persistent Shield
721 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
722 break;
723 default:
724 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
725 break;
727 return;
729 case 15998: // Capture Worg Pup
730 case 29435: // Capture Female Kaliri Hatchling
732 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
733 return;
735 Creature* creatureTarget = (Creature*)unitTarget;
736 creatureTarget->setDeathState(JUST_DIED);
737 creatureTarget->RemoveCorpse();
738 creatureTarget->SetHealth(0); // just for nice GM-mode view
739 return;
741 case 16589: // Noggenfogger Elixir
743 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
744 return;
746 uint32 spell_id = 0;
747 switch(urand(1,3))
749 case 1: spell_id = 16595; break;
750 case 2: spell_id = 16593; break;
751 default:spell_id = 16591; break;
754 m_caster->CastSpell(m_caster,spell_id,true,NULL);
755 return;
757 case 17251: // Spirit Healer Res
759 if(!unitTarget || !m_originalCaster)
760 return;
762 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
764 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
765 data << unitTarget->GetGUID();
766 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
768 return;
770 case 17271: // Test Fetid Skull
772 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
773 return;
775 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
777 m_caster->CastSpell(m_caster,spell_id,true,NULL);
778 return;
780 case 20577: // Cannibalize
781 if (unitTarget)
782 m_caster->CastSpell(m_caster,20578,false,NULL);
783 return;
784 case 23019: // Crystal Prison Dummy DND
786 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
787 return;
789 Creature* creatureTarget = (Creature*)unitTarget;
790 if(creatureTarget->isPet())
791 return;
793 GameObject* pGameObj = new GameObject;
795 Map *map = creatureTarget->GetMap();
797 // create before death for get proper coordinates
798 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
799 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
800 creatureTarget->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY) )
802 delete pGameObj;
803 return;
806 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
807 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
808 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
809 pGameObj->SetSpellId(m_spellInfo->Id);
811 creatureTarget->setDeathState(JUST_DIED);
812 creatureTarget->RemoveCorpse();
813 creatureTarget->SetHealth(0); // just for nice GM-mode view
815 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy");
816 map->Add(pGameObj);
818 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
819 data << uint64(pGameObj->GetGUID());
820 m_caster->SendMessageToSet(&data,true);
822 return;
824 case 23074: // Arcanite Dragonling
825 if (!m_CastItem) return;
826 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
827 return;
828 case 23075: // Mithril Mechanical Dragonling
829 if (!m_CastItem) return;
830 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
831 return;
832 case 23076: // Mechanical Dragonling
833 if (!m_CastItem) return;
834 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
835 return;
836 case 23133: // Gnomish Battle Chicken
837 if (!m_CastItem) return;
838 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
839 return;
840 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
842 int32 r = irand(0, 119);
843 if ( r < 20 ) // 1/6 polymorph
844 m_caster->CastSpell(m_caster,23444,true);
845 else if ( r < 100 ) // 4/6 evil twin
846 m_caster->CastSpell(m_caster,23445,true);
847 else // 1/6 miss the target
848 m_caster->CastSpell(m_caster,36902,true);
849 return;
851 case 23453: // Ultrasafe Transporter: Gadgetzan
852 if ( roll_chance_i(50) ) // success
853 m_caster->CastSpell(m_caster,23441,true);
854 else // failure
855 m_caster->CastSpell(m_caster,23446,true);
856 return;
857 case 23645: // Hourglass Sand
858 m_caster->RemoveAurasDueToSpell(23170);
859 return;
860 case 23725: // Gift of Life (warrior bwl trinket)
861 m_caster->CastSpell(m_caster,23782,true);
862 m_caster->CastSpell(m_caster,23783,true);
863 return;
864 case 25860: // Reindeer Transformation
866 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
867 return;
869 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
870 float speed = m_caster->GetSpeedRate(MOVE_RUN);
872 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
874 //5 different spells used depending on mounted speed and if mount can fly or not
875 if (flyspeed >= 4.1f)
876 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
877 else if (flyspeed >= 3.8f)
878 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
879 else if (flyspeed >= 1.6f)
880 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
881 else if (speed >= 2.0f)
882 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
883 else
884 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
886 return;
888 //case 26074: // Holiday Cheer
889 // return; -- implemented at client side
890 case 28006: // Arcane Cloaking
892 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER )
893 m_caster->CastSpell(unitTarget,29294,true);
894 return;
896 case 28730: // Arcane Torrent (Mana)
898 Aura * dummy = m_caster->GetDummyAura(28734);
899 if (dummy)
901 int32 bp = damage * dummy->GetStackAmount();
902 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
903 m_caster->RemoveAurasDueToSpell(28734);
905 return;
907 case 29200: // Purify Helboar Meat
909 if( m_caster->GetTypeId() != TYPEID_PLAYER )
910 return;
912 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
914 m_caster->CastSpell(m_caster,spell_id,true,NULL);
915 return;
917 case 29858: // Soulshatter
918 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
919 m_caster->CastSpell(unitTarget,32835,true);
920 return;
921 case 30458: // Nigh Invulnerability
922 if (!m_CastItem) return;
923 if(roll_chance_i(86)) // success
924 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
925 else // backfire in 14% casts
926 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
927 return;
928 case 30507: // Poultryizer
929 if (!m_CastItem) return;
930 if(roll_chance_i(80)) // success
931 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
932 else // backfire 20%
933 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
934 return;
935 case 33060: // Make a Wish
937 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
938 return;
940 uint32 spell_id = 0;
942 switch(urand(1,5))
944 case 1: spell_id = 33053; break;
945 case 2: spell_id = 33057; break;
946 case 3: spell_id = 33059; break;
947 case 4: spell_id = 33062; break;
948 case 5: spell_id = 33064; break;
951 m_caster->CastSpell(m_caster,spell_id,true,NULL);
952 return;
954 case 35745:
956 uint32 spell_id;
957 switch(m_caster->GetAreaId())
959 case 3900: spell_id = 35743; break;
960 case 3742: spell_id = 35744; break;
961 default: return;
964 m_caster->CastSpell(m_caster,spell_id,true);
965 return;
967 case 37674: // Chaos Blast
969 if(!unitTarget)
970 return;
972 int32 basepoints0 = 100;
973 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
974 return;
976 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
978 // selecting one from Bloodstained Fortune item
979 uint32 newitemid;
980 switch(urand(1,20))
982 case 1: newitemid = 32688; break;
983 case 2: newitemid = 32689; break;
984 case 3: newitemid = 32690; break;
985 case 4: newitemid = 32691; break;
986 case 5: newitemid = 32692; break;
987 case 6: newitemid = 32693; break;
988 case 7: newitemid = 32700; break;
989 case 8: newitemid = 32701; break;
990 case 9: newitemid = 32702; break;
991 case 10: newitemid = 32703; break;
992 case 11: newitemid = 32704; break;
993 case 12: newitemid = 32705; break;
994 case 13: newitemid = 32706; break;
995 case 14: newitemid = 32707; break;
996 case 15: newitemid = 32708; break;
997 case 16: newitemid = 32709; break;
998 case 17: newitemid = 32710; break;
999 case 18: newitemid = 32711; break;
1000 case 19: newitemid = 32712; break;
1001 case 20: newitemid = 32713; break;
1002 default:
1003 return;
1006 DoCreateItem(i,newitemid);
1007 return;
1009 // Demon Broiled Surprise
1010 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1011 case 43723:
1013 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1014 return;
1016 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1017 return;
1020 case 44875: // Complete Raptor Capture
1022 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1023 return;
1025 Creature* creatureTarget = (Creature*)unitTarget;
1027 creatureTarget->setDeathState(JUST_DIED);
1028 creatureTarget->RemoveCorpse();
1029 creatureTarget->SetHealth(0); // just for nice GM-mode view
1031 //cast spell Raptor Capture Credit
1032 m_caster->CastSpell(m_caster,42337,true,NULL);
1033 return;
1035 case 34665: //Administer Antidote
1037 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1038 return;
1040 if(!unitTarget)
1041 return;
1043 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1044 if(!tempSummon)
1045 return;
1047 uint32 health = tempSummon->GetHealth();
1049 float x = tempSummon->GetPositionX();
1050 float y = tempSummon->GetPositionY();
1051 float z = tempSummon->GetPositionZ();
1052 float o = tempSummon->GetOrientation();
1053 tempSummon->UnSummon();
1055 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1056 if (!pCreature)
1057 return;
1059 pCreature->SetHealth(health);
1060 ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992,pCreature);
1062 if (pCreature->AI())
1063 pCreature->AI()->AttackStart(m_caster);
1065 return;
1067 case 44997: // Converting Sentry
1069 //Converted Sentry Credit
1070 m_caster->CastSpell(m_caster, 45009, true);
1071 return;
1073 case 45030: // Impale Emissary
1075 // Emissary of Hate Credit
1076 m_caster->CastSpell(m_caster, 45088, true);
1077 return;
1079 case 50243: // Teach Language
1081 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1082 return;
1084 // spell has a 1/3 chance to trigger one of the below
1085 if(roll_chance_i(66))
1086 return;
1087 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1089 // 1000001 - gnomish binary
1090 m_caster->CastSpell(m_caster, 50242, true);
1092 else
1094 // 01001000 - goblin binary
1095 m_caster->CastSpell(m_caster, 50246, true);
1098 return;
1100 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1102 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1103 return;
1105 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1106 bg->EventPlayerDroppedFlag((Player*)m_caster);
1108 m_caster->CastSpell(m_caster, 30452, true, NULL);
1109 return;
1111 case 51592: // Pickup Primordial Hatchling
1113 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1114 return;
1116 Creature* creatureTarget = (Creature*)unitTarget;
1118 creatureTarget->setDeathState(JUST_DIED);
1119 creatureTarget->RemoveCorpse();
1120 creatureTarget->SetHealth(0); // just for nice GM-mode view
1121 return;
1124 case 52308:
1126 switch(i)
1128 case 0:
1130 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
1131 uint32 reqAuraID = m_spellInfo->CalculateSimpleValue(1);
1133 if (m_caster->HasAura(reqAuraID,0))
1134 m_caster->CastSpell(m_caster,spellID,true,NULL);
1135 return;
1137 case 1:
1138 return; // additional data for dummy[0]
1140 return;
1142 case 53341:
1143 case 53343:
1145 m_caster->CastSpell(m_caster,54586,true);
1146 return;
1148 case 58418: // Portal to Orgrimmar
1149 case 58420: // Portal to Stormwind
1150 return; // implemented in EffectScript[0]
1153 //All IconID Check in there
1154 switch(m_spellInfo->SpellIconID)
1156 // Berserking (troll racial traits)
1157 case 1661:
1159 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1160 int32 melee_mod = 10;
1161 if (healthPerc <= 40)
1162 melee_mod = 30;
1163 if (healthPerc < 100 && healthPerc > 40)
1164 melee_mod = 10+(100-healthPerc)/3;
1166 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1167 int32 hasteModBasePoints1 = (5-melee_mod);
1168 int32 hasteModBasePoints2 = 5;
1170 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1171 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1172 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1173 return;
1176 break;
1178 case SPELLFAMILY_MAGE:
1179 switch(m_spellInfo->Id )
1181 case 11958: // Cold Snap
1183 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1184 return;
1186 // immediately finishes the cooldown on Frost spells
1187 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1188 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1190 if (itr->second->state == PLAYERSPELL_REMOVED)
1191 continue;
1193 uint32 classspell = itr->first;
1194 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1196 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1197 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1198 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1200 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1202 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1203 data << uint32(classspell);
1204 data << uint64(m_caster->GetGUID());
1205 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1208 return;
1210 case 32826:
1212 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1214 //Polymorph Cast Visual Rank 1
1215 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1216 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1218 return;
1221 break;
1222 case SPELLFAMILY_WARRIOR:
1223 // Charge
1224 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1226 int32 chargeBasePoints0 = damage;
1227 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1228 return;
1230 // Execute
1231 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1233 if(!unitTarget)
1234 return;
1236 uint32 rage = m_caster->GetPower(POWER_RAGE);
1237 // Glyph of Execution bonus
1238 if (Aura *aura = m_caster->GetDummyAura(58367))
1239 rage+=aura->GetModifier()->m_amount;
1241 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1242 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1243 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1244 m_caster->SetPower(POWER_RAGE,0);
1245 return;
1247 // Slam
1248 if(m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL)
1250 if(!unitTarget)
1251 return;
1252 m_damage+=m_caster->CalculateDamage(m_attackType, false);
1253 m_damage+=damage;
1254 return;
1256 // Concussion Blow
1257 if(m_spellInfo->SpellFamilyFlags & 0x0000000004000000LL)
1259 m_damage+= uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
1260 return;
1262 switch(m_spellInfo->Id)
1264 // Warrior's Wrath
1265 case 21977:
1267 if(!unitTarget)
1268 return;
1269 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1270 return;
1272 // Last Stand
1273 case 12975:
1275 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1276 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1277 return;
1279 // Bloodthirst
1280 case 23881:
1282 m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
1283 return;
1286 break;
1287 case SPELLFAMILY_WARLOCK:
1288 // Life Tap
1289 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1291 // In 303 exist spirit depend
1292 uint32 spirit = uint32(m_caster->GetStat(STAT_SPIRIT));
1293 switch (m_spellInfo->Id)
1295 case 1454: damage+=spirit; break;
1296 case 1455: damage+=spirit*15/10; break;
1297 case 1456: damage+=spirit*2; break;
1298 case 11687: damage+=spirit*25/10; break;
1299 case 11688:
1300 case 11689:
1301 case 27222:
1302 case 57946: damage+=spirit*3; break;
1303 default:
1304 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1305 return;
1307 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1308 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1309 if(unitTarget && (int32(unitTarget->GetHealth()) > damage))
1311 // Shouldn't Appear in Combat Log
1312 unitTarget->ModifyHealth(-damage);
1314 int32 mana = damage;
1315 // Improved Life Tap mod
1316 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1317 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1319 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1320 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1322 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1324 // Mana Feed
1325 int32 manaFeedVal = 0;
1326 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1327 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1329 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1330 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1332 if(manaFeedVal > 0)
1334 manaFeedVal = manaFeedVal * mana / 100;
1335 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1338 else
1339 SendCastResult(SPELL_FAILED_FIZZLE);
1340 return;
1342 break;
1343 case SPELLFAMILY_PRIEST:
1344 // Penance
1345 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1347 if (!unitTarget)
1348 return;
1350 int hurt = 0;
1351 int heal = 0;
1352 switch(m_spellInfo->Id)
1354 case 47540: hurt = 47758; heal = 47757; break;
1355 case 53005: hurt = 53001; heal = 52986; break;
1356 case 53006: hurt = 53002; heal = 52987; break;
1357 case 53007: hurt = 53003; heal = 52988; break;
1358 default:
1359 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1360 return;
1362 if (m_caster->IsFriendlyTo(unitTarget))
1363 m_caster->CastSpell(unitTarget, heal, true, 0);
1364 else
1365 m_caster->CastSpell(unitTarget, hurt, true, 0);
1366 return;
1368 break;
1369 case SPELLFAMILY_DRUID:
1370 // Starfall
1371 if (m_spellInfo->SpellFamilyFlags2 & 0x00000100LL)
1373 //Shapeshifting into an animal form or mounting cancels the effect.
1374 if(m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
1376 if(m_triggeredByAuraSpell)
1377 m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
1378 return;
1381 //Any effect which causes you to lose control of your character will supress the starfall effect.
1382 if(m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED))
1383 return;
1385 switch(m_spellInfo->Id)
1387 case 50286: m_caster->CastSpell(unitTarget, 50288, true); return;
1388 case 53196: m_caster->CastSpell(unitTarget, 53191, true); return;
1389 case 53197: m_caster->CastSpell(unitTarget, 53194, true); return;
1390 case 53198: m_caster->CastSpell(unitTarget, 53195, true); return;
1391 default:
1392 sLog.outError("Spell::EffectDummy: Unhandeled Starfall spell rank %u",m_spellInfo->Id);
1393 return;
1396 break;
1397 case SPELLFAMILY_ROGUE:
1398 switch(m_spellInfo->Id )
1400 case 5938: // Shiv
1402 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1403 return;
1405 Player *pCaster = ((Player*)m_caster);
1407 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1408 if(!item)
1409 return;
1411 // all poison enchantments is temporary
1412 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1413 if(!enchant_id)
1414 return;
1416 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1417 if(!pEnchant)
1418 return;
1420 for (int s=0;s<3;s++)
1422 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1423 continue;
1425 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1426 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1427 continue;
1429 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1432 m_caster->CastSpell(unitTarget, 5940, true);
1433 return;
1435 case 14185: // Preparation Rogue
1437 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1438 return;
1440 //immediately finishes the cooldown on certain Rogue abilities
1441 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1442 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1444 uint32 classspell = itr->first;
1445 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1447 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1449 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1451 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1452 data << uint32(classspell);
1453 data << uint64(m_caster->GetGUID());
1454 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1457 return;
1459 case 31231: // Cheat Death
1461 m_caster->CastSpell(m_caster,45182,true);
1462 return;
1465 break;
1466 case SPELLFAMILY_HUNTER:
1467 // Steady Shot
1468 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1470 if( !unitTarget || !unitTarget->isAlive())
1471 return;
1473 bool found = false;
1475 // check dazed affect
1476 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1477 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1479 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1481 found = true;
1482 break;
1486 if(found)
1487 m_damage+= damage;
1488 return;
1491 switch(m_spellInfo->Id)
1493 case 23989: //Readiness talent
1495 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1496 return;
1498 //immediately finishes the cooldown for hunter abilities
1499 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1500 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1502 uint32 classspell = itr->first;
1503 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1505 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1507 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1509 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1510 data << uint32(classspell);
1511 data << uint64(m_caster->GetGUID());
1512 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1515 return;
1517 case 37506: // Scatter Shot
1519 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1520 return;
1522 // break Auto Shot and autohit
1523 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1524 m_caster->AttackStop();
1525 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1526 return;
1529 break;
1530 case SPELLFAMILY_PALADIN:
1531 switch(m_spellInfo->SpellIconID)
1533 case 156: // Holy Shock
1535 if(!unitTarget)
1536 return;
1538 int hurt = 0;
1539 int heal = 0;
1541 switch(m_spellInfo->Id)
1543 case 20473: hurt = 25912; heal = 25914; break;
1544 case 20929: hurt = 25911; heal = 25913; break;
1545 case 20930: hurt = 25902; heal = 25903; break;
1546 case 27174: hurt = 27176; heal = 27175; break;
1547 case 33072: hurt = 33073; heal = 33074; break;
1548 case 48824: hurt = 48822; heal = 48820; break;
1549 case 48825: hurt = 48823; heal = 48821; break;
1550 default:
1551 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1552 return;
1555 if(m_caster->IsFriendlyTo(unitTarget))
1556 m_caster->CastSpell(unitTarget, heal, true, 0);
1557 else
1558 m_caster->CastSpell(unitTarget, hurt, true, 0);
1560 return;
1562 case 561: // Judgement of command
1564 if(!unitTarget)
1565 return;
1567 uint32 spell_id = m_currentBasePoints[i]+1;
1568 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1569 if(!spell_proto)
1570 return;
1572 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1574 // decreased damage (/2) for non-stunned target.
1575 SpellModifier *mod = new SpellModifier;
1576 mod->op = SPELLMOD_DAMAGE;
1577 mod->value = -50;
1578 mod->type = SPELLMOD_PCT;
1579 mod->spellId = m_spellInfo->Id;
1580 mod->mask = 0x0000020000000000LL;
1581 mod->mask2= 0LL;
1583 ((Player*)m_caster)->AddSpellMod(mod, true);
1584 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1585 // mod deleted
1586 ((Player*)m_caster)->AddSpellMod(mod, false);
1588 else
1589 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1591 return;
1595 switch(m_spellInfo->Id)
1597 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1598 case 20187:
1600 if (!unitTarget)
1601 return;
1602 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1603 return;
1605 case 31789: // Righteous Defense (step 1)
1607 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1609 // non-standard cast requirement check
1610 if (!unitTarget || unitTarget->getAttackers().empty())
1612 // clear cooldown at fail
1613 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1615 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1617 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1618 data << uint32(m_spellInfo->Id);
1619 data << uint64(m_caster->GetGUID());
1620 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1623 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1624 return;
1627 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1628 // Clear targets for eff 1
1629 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1630 ihit->effectMask &= ~(1<<1);
1632 // not empty (checked)
1633 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1635 // chance to be selected from list
1636 float chance = 100.0f/attackers.size();
1637 uint32 count=0;
1638 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1640 if(!roll_chance_f(chance))
1641 continue;
1642 ++count;
1643 AddUnitTarget((*aItr), 1);
1646 // now let next effect cast spell at each target.
1647 return;
1649 case 37877: // Blessing of Faith
1651 if(!unitTarget)
1652 return;
1654 uint32 spell_id = 0;
1655 switch(unitTarget->getClass())
1657 case CLASS_DRUID: spell_id = 37878; break;
1658 case CLASS_PALADIN: spell_id = 37879; break;
1659 case CLASS_PRIEST: spell_id = 37880; break;
1660 case CLASS_SHAMAN: spell_id = 37881; break;
1661 default: return; // ignore for not healing classes
1664 m_caster->CastSpell(m_caster,spell_id,true);
1665 return;
1668 break;
1669 case SPELLFAMILY_SHAMAN:
1670 //Shaman Rockbiter Weapon
1671 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1673 // TODO: use expect spell for enchant (if exist talent)
1674 // In 3.0.3 no mods present for rockbiter
1675 uint32 spell_id = 0;
1676 switch(m_spellInfo->Id)
1678 case 8017: spell_id = 36494; break; // Rank 1
1679 case 8018: spell_id = 36750; break; // Rank 2
1680 case 8019: spell_id = 36755; break; // Rank 3
1681 case 10399: spell_id = 36759; break; // Rank 4
1682 default:
1683 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1684 return;
1687 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1689 if(!spellInfo)
1691 sLog.outError("WORLD: unknown spell id %i", spell_id);
1692 return;
1695 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1696 return;
1698 for(int j = BASE_ATTACK; j <= OFF_ATTACK; ++j)
1700 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(j)))
1702 if(item->IsFitToSpellRequirements(m_spellInfo))
1704 Spell *spell = new Spell(m_caster, spellInfo, true);
1706 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1707 // at calculation applied affect from Elemental Weapons talent
1708 // real enchantment damage-1
1709 spell->m_currentBasePoints[1] = damage-1;
1711 SpellCastTargets targets;
1712 targets.setItemTarget( item );
1713 spell->prepare(&targets);
1717 return;
1719 // Healing Stream Totem
1720 if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
1722 m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1723 return;
1725 // Mana Spring Totem
1726 if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
1728 if(unitTarget->getPowerType()!=POWER_MANA)
1729 return;
1730 m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1731 return;
1733 if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
1735 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1736 return;
1737 // Glyph of Mana Tide
1738 Unit *owner = m_caster->GetOwner();
1739 if (owner)
1740 if (Aura *dummy = owner->GetDummyAura(55441))
1741 damage+=dummy->GetModifier()->m_amount;
1742 // Regenerate 6% of Total Mana Every 3 secs
1743 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1744 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1745 return;
1747 // Lava Lash
1748 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1750 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1751 return;
1752 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1753 if (item)
1755 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1756 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1757 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1759 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1760 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1761 (*itr)->GetCastItemGUID() == item->GetGUID())
1763 m_damage += m_damage * damage / 100;
1764 return;
1768 return;
1770 break;
1771 case SPELLFAMILY_DEATHKNIGHT:
1772 // Death Coil
1773 if(m_spellInfo->SpellFamilyFlags & 0x002000LL)
1775 if(m_caster->IsFriendlyTo(unitTarget))
1777 if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
1778 return;
1780 int32 bp = damage * 1.5f;
1781 m_caster->CastCustomSpell(unitTarget,47633,&bp,NULL,NULL,true);
1783 else
1785 int32 bp = damage;
1786 m_caster->CastCustomSpell(unitTarget,47632,&bp,NULL,NULL,true);
1788 return;
1790 break;
1793 // pet auras
1794 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1796 m_caster->AddPetAura(petSpell);
1797 return;
1800 // Script based implementation. Must be used only for not good for implementation in core spell effects
1801 // So called only for not proccessed cases
1802 if(gameObjTarget)
1803 Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget);
1804 else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT)
1805 Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget);
1806 else if(itemTarget)
1807 Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget);
1810 void Spell::EffectTriggerSpellWithValue(uint32 i)
1812 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1814 // normal case
1815 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1817 if(!spellInfo)
1819 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1820 return;
1823 int32 bp = damage;
1824 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1827 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1829 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1830 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1832 if(!spellInfo)
1834 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1835 return;
1838 finish();
1839 Spell *spell = new Spell(m_caster, spellInfo, true);
1841 SpellCastTargets targets;
1842 targets.setUnitTarget( unitTarget);
1843 spell->prepare(&targets);
1845 m_caster->SetCurrentCastedSpell(spell);
1846 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1850 void Spell::EffectForceCast(uint32 i)
1852 if( !unitTarget )
1853 return;
1855 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1857 // normal case
1858 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1860 if(!spellInfo)
1862 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1863 return;
1866 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1869 void Spell::EffectTriggerSpell(uint32 i)
1871 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1873 // special cases
1874 switch(triggered_spell_id)
1876 // Vanish
1877 case 18461:
1879 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1880 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1881 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1883 // if this spell is given to NPC it must handle rest by it's own AI
1884 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1885 return;
1887 // get highest rank of the Stealth spell
1888 uint32 spellId = 0;
1889 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1890 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1892 // only highest rank is shown in spell book, so simply check if shown in spell book
1893 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1894 continue;
1896 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1897 if (!spellInfo)
1898 continue;
1900 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1902 spellId = spellInfo->Id;
1903 break;
1907 // no Stealth spell found
1908 if (!spellId)
1909 return;
1911 // reset cooldown on it if needed
1912 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1913 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1915 m_caster->CastSpell(m_caster, spellId, true);
1916 return;
1918 // just skip
1919 case 23770: // Sayge's Dark Fortune of *
1920 // not exist, common cooldown can be implemented in scripts if need.
1921 return;
1922 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1923 case 29284:
1925 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1926 if (!spell)
1927 return;
1929 for (int j=0; j < spell->StackAmount; ++j)
1930 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1931 return;
1933 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1934 case 29286:
1936 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1937 if (!spell)
1938 return;
1940 for (int j=0; j < spell->StackAmount; ++j)
1941 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1942 return;
1944 // Righteous Defense
1945 case 31980:
1947 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1948 return;
1950 // Cloak of Shadows
1951 case 35729 :
1953 Unit::AuraMap& Auras = m_caster->GetAuras();
1954 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1956 // remove all harmful spells on you...
1957 if( // ignore positive and passive auras
1958 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1959 // ignore physical auras
1960 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1962 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1963 iter = Auras.begin();
1966 return;
1968 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1969 case 41967:
1971 if (Unit *pet = m_caster->GetPet())
1972 pet->CastSpell(pet, 28305, true);
1973 return;
1977 // normal case
1978 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1980 if(!spellInfo)
1982 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1983 return;
1986 // some triggered spells require specific equipment
1987 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1989 // main hand weapon required
1990 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1992 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1994 // skip spell if no weapon in slot or broken
1995 if(!item || item->IsBroken() )
1996 return;
1998 // skip spell if weapon not fit to triggered spell
1999 if(!item->IsFitToSpellRequirements(spellInfo))
2000 return;
2003 // offhand hand weapon required
2004 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
2006 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
2008 // skip spell if no weapon in slot or broken
2009 if(!item || item->IsBroken() )
2010 return;
2012 // skip spell if weapon not fit to triggered spell
2013 if(!item->IsFitToSpellRequirements(spellInfo))
2014 return;
2018 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
2019 bool instant = false;
2020 for(uint32 j = i+1; j < 3; ++j)
2022 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
2024 instant = true;
2025 break;
2029 if(instant)
2031 if (unitTarget)
2032 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
2034 else
2035 m_TriggerSpells.push_back(spellInfo);
2038 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
2040 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
2042 // normal case
2043 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
2045 if(!spellInfo)
2047 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
2048 m_spellInfo->Id,effect_idx,triggered_spell_id);
2049 return;
2052 if (m_CastItem)
2053 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
2055 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
2058 void Spell::EffectJump(uint32 i)
2060 if(m_caster->isInFlight())
2061 return;
2063 // Init dest coordinates
2064 float x,y,z,o;
2065 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
2067 x = m_targets.m_destX;
2068 y = m_targets.m_destY;
2069 z = m_targets.m_destZ;
2071 if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM)
2073 // explicit cast data from client or server-side cast
2074 // some spell at client send caster
2075 Unit* pTarget = NULL;
2076 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster)
2077 pTarget = m_targets.getUnitTarget();
2078 else if(unitTarget->getVictim())
2079 pTarget = m_caster->getVictim();
2080 else if(m_caster->GetTypeId() == TYPEID_PLAYER)
2081 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2083 o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
2085 else
2086 o = m_caster->GetOrientation();
2088 else if(unitTarget)
2090 unitTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2091 o = m_caster->GetOrientation();
2093 else if(gameObjTarget)
2095 gameObjTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2096 o = m_caster->GetOrientation();
2098 else
2100 sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id );
2101 return;
2104 m_caster->NearTeleportTo(x,y,z,o,true);
2107 void Spell::EffectTeleportUnits(uint32 i)
2109 if(!unitTarget || unitTarget->isInFlight())
2110 return;
2112 switch (m_spellInfo->EffectImplicitTargetB[i])
2114 case TARGET_INNKEEPER_COORDINATES:
2116 // Only players can teleport to innkeeper
2117 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2118 return;
2120 ((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);
2121 return;
2123 case TARGET_AREAEFFECT_INSTANT: // in all cases first TARGET_TABLE_X_Y_Z_COORDINATES
2124 case TARGET_TABLE_X_Y_Z_COORDINATES:
2126 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2127 if(!st)
2129 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id );
2130 return;
2133 if(st->target_mapId==unitTarget->GetMapId())
2134 unitTarget->NearTeleportTo(st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster);
2135 else if(unitTarget->GetTypeId()==TYPEID_PLAYER)
2136 ((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);
2137 break;
2139 case TARGET_BEHIND_VICTIM:
2141 Unit *pTarget = NULL;
2143 // explicit cast data from client or server-side cast
2144 // some spell at client send caster
2145 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=unitTarget)
2146 pTarget = m_targets.getUnitTarget();
2147 else if(unitTarget->getVictim())
2148 pTarget = unitTarget->getVictim();
2149 else if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2150 pTarget = ObjectAccessor::GetUnit(*unitTarget, ((Player*)unitTarget)->GetSelection());
2152 // Init dest coordinates
2153 float x = m_targets.m_destX;
2154 float y = m_targets.m_destY;
2155 float z = m_targets.m_destZ;
2156 float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation();
2157 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2158 return;
2160 default:
2162 // If not exist data for dest location - return
2163 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2165 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2166 return;
2168 // Init dest coordinates
2169 float x = m_targets.m_destX;
2170 float y = m_targets.m_destY;
2171 float z = m_targets.m_destZ;
2172 float orientation = unitTarget->GetOrientation();
2173 // Teleport
2174 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2175 return;
2179 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2180 switch ( m_spellInfo->Id )
2182 // Dimensional Ripper - Everlook
2183 case 23442:
2185 int32 r = irand(0, 119);
2186 if ( r >= 70 ) // 7/12 success
2188 if ( r < 100 ) // 4/12 evil twin
2189 m_caster->CastSpell(m_caster,23445,true);
2190 else // 1/12 fire
2191 m_caster->CastSpell(m_caster,23449,true);
2193 return;
2195 // Ultrasafe Transporter: Toshley's Station
2196 case 36941:
2198 if ( roll_chance_i(50) ) // 50% success
2200 int32 rand_eff = urand(1,7);
2201 switch ( rand_eff )
2203 case 1:
2204 // soul split - evil
2205 m_caster->CastSpell(m_caster,36900,true);
2206 break;
2207 case 2:
2208 // soul split - good
2209 m_caster->CastSpell(m_caster,36901,true);
2210 break;
2211 case 3:
2212 // Increase the size
2213 m_caster->CastSpell(m_caster,36895,true);
2214 break;
2215 case 4:
2216 // Decrease the size
2217 m_caster->CastSpell(m_caster,36893,true);
2218 break;
2219 case 5:
2220 // Transform
2222 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2223 m_caster->CastSpell(m_caster,36897,true);
2224 else
2225 m_caster->CastSpell(m_caster,36899,true);
2226 break;
2228 case 6:
2229 // chicken
2230 m_caster->CastSpell(m_caster,36940,true);
2231 break;
2232 case 7:
2233 // evil twin
2234 m_caster->CastSpell(m_caster,23445,true);
2235 break;
2238 return;
2240 // Dimensional Ripper - Area 52
2241 case 36890:
2243 if ( roll_chance_i(50) ) // 50% success
2245 int32 rand_eff = urand(1,4);
2246 switch ( rand_eff )
2248 case 1:
2249 // soul split - evil
2250 m_caster->CastSpell(m_caster,36900,true);
2251 break;
2252 case 2:
2253 // soul split - good
2254 m_caster->CastSpell(m_caster,36901,true);
2255 break;
2256 case 3:
2257 // Increase the size
2258 m_caster->CastSpell(m_caster,36895,true);
2259 break;
2260 case 4:
2261 // Transform
2263 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2264 m_caster->CastSpell(m_caster,36897,true);
2265 else
2266 m_caster->CastSpell(m_caster,36899,true);
2267 break;
2271 return;
2276 void Spell::EffectApplyAura(uint32 i)
2278 if(!unitTarget)
2279 return;
2281 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2282 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2283 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2284 return;
2286 Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
2287 if(!caster)
2288 return;
2290 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2292 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2294 // Now Reduce spell duration using data received at spell hit
2295 int32 duration = Aur->GetAuraMaxDuration();
2296 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2297 Aur->setDiminishGroup(m_diminishGroup);
2299 // if Aura removed and deleted, do not continue.
2300 if(duration== 0 && !(Aur->IsPermanent()))
2302 delete Aur;
2303 return;
2306 if(duration != Aur->GetAuraMaxDuration())
2308 Aur->SetAuraMaxDuration(duration);
2309 Aur->SetAuraDuration(duration);
2312 bool added = unitTarget->AddAura(Aur);
2314 // Aura not added and deleted in AddAura call;
2315 if (!added)
2316 return;
2318 // found crash at character loading, broken pointer to Aur...
2319 // Aur was deleted in AddAura()...
2320 if(!Aur)
2321 return;
2323 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2324 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2325 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2328 void Spell::EffectUnlearnSpecialization( uint32 i )
2330 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2331 return;
2333 Player *_player = (Player*)unitTarget;
2334 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2336 _player->removeSpell(spellToUnlearn);
2338 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2341 void Spell::EffectPowerDrain(uint32 i)
2343 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2344 return;
2346 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2348 if(!unitTarget)
2349 return;
2350 if(!unitTarget->isAlive())
2351 return;
2352 if(unitTarget->getPowerType() != drain_power)
2353 return;
2354 if(damage < 0)
2355 return;
2357 uint32 curPower = unitTarget->GetPower(drain_power);
2359 //add spell damage bonus
2360 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2362 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2363 uint32 power = damage;
2364 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2365 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2367 int32 new_damage;
2368 if(curPower < power)
2369 new_damage = curPower;
2370 else
2371 new_damage = power;
2373 unitTarget->ModifyPower(drain_power,-new_damage);
2375 // Don`t restore from self drain
2376 if(drain_power == POWER_MANA && m_caster != unitTarget)
2378 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2379 if(manaMultiplier==0)
2380 manaMultiplier = 1;
2382 if(Player *modOwner = m_caster->GetSpellModOwner())
2383 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2385 int32 gain = int32(new_damage*manaMultiplier);
2387 m_caster->ModifyPower(POWER_MANA,gain);
2388 //send log
2389 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2393 void Spell::EffectSendEvent(uint32 EffectIndex)
2396 we do not handle a flag dropping or clicking on flag in battleground by sendevent system
2398 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2399 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2402 void Spell::EffectPowerBurn(uint32 i)
2404 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2405 return;
2407 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2409 if(!unitTarget)
2410 return;
2411 if(!unitTarget->isAlive())
2412 return;
2413 if(unitTarget->getPowerType()!=powertype)
2414 return;
2415 if(damage < 0)
2416 return;
2418 // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
2419 if(m_spellInfo->ManaCostPercentage)
2421 uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
2422 damage = unitTarget->GetMaxPower(powertype) * damage / 100;
2423 if(damage > maxdamage) damage = maxdamage;
2426 int32 curPower = int32(unitTarget->GetPower(powertype));
2428 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2429 uint32 power = damage;
2430 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2431 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2433 int32 new_damage = (curPower < power) ? curPower : power;
2435 unitTarget->ModifyPower(powertype,-new_damage);
2436 float multiplier = m_spellInfo->EffectMultipleValue[i];
2438 if(Player *modOwner = m_caster->GetSpellModOwner())
2439 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2441 new_damage = int32(new_damage*multiplier);
2442 m_damage+=new_damage;
2445 void Spell::EffectHeal( uint32 /*i*/ )
2447 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2449 // Try to get original caster
2450 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2452 // Skip if m_originalCaster not available
2453 if (!caster)
2454 return;
2456 int32 addhealth = damage;
2458 // Vessel of the Naaru (Vial of the Sunwell trinket)
2459 if (m_spellInfo->Id == 45064)
2461 // Amount of heal - depends from stacked Holy Energy
2462 int damageAmount = 0;
2463 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2464 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2465 if((*i)->GetId() == 45062)
2466 damageAmount+=(*i)->GetModifier()->m_amount;
2467 if (damageAmount)
2468 m_caster->RemoveAurasDueToSpell(45062);
2470 addhealth += damageAmount;
2472 // Swiftmend - consumes Regrowth or Rejuvenation
2473 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2475 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2476 // find most short by duration
2477 Aura *targetAura = NULL;
2478 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2480 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2481 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2483 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2484 targetAura = *i;
2488 if(!targetAura)
2490 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2491 return;
2493 int idx = 0;
2494 while(idx < 3)
2496 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2497 break;
2498 idx++;
2501 int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
2502 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2503 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2505 addhealth += tickheal * tickcount;
2507 else
2508 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
2510 m_healing+=addhealth;
2514 void Spell::EffectHealPct( uint32 /*i*/ )
2516 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2518 // Try to get original caster
2519 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2521 // Skip if m_originalCaster not available
2522 if (!caster)
2523 return;
2525 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2526 if(Player* modOwner = m_caster->GetSpellModOwner())
2527 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this);
2529 int32 gain = caster->DealHeal(unitTarget, addhealth, m_spellInfo);
2530 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2534 void Spell::EffectHealMechanical( uint32 /*i*/ )
2536 // Mechanic creature type should be correctly checked by targetCreatureType field
2537 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2539 // Try to get original caster
2540 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2542 // Skip if m_originalCaster not available
2543 if (!caster)
2544 return;
2546 uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
2547 caster->DealHeal(unitTarget, addhealth, m_spellInfo);
2551 void Spell::EffectHealthLeech(uint32 i)
2553 if(!unitTarget)
2554 return;
2555 if(!unitTarget->isAlive())
2556 return;
2558 if(damage < 0)
2559 return;
2561 sLog.outDebug("HealthLeech :%i", damage);
2563 float multiplier = m_spellInfo->EffectMultipleValue[i];
2565 if(Player *modOwner = m_caster->GetSpellModOwner())
2566 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2568 int32 new_damage = int32(damage*multiplier);
2569 uint32 curHealth = unitTarget->GetHealth();
2570 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage );
2571 if(curHealth < new_damage)
2572 new_damage = curHealth;
2574 if(m_caster->isAlive())
2576 new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
2577 m_caster->DealHeal(m_caster, uint32(new_damage), m_spellInfo);
2579 // m_healthLeech+=tmpvalue;
2580 // m_damage+=new_damage;
2583 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2585 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2586 return;
2588 Player* player = (Player*)unitTarget;
2590 uint32 newitemid = itemtype;
2591 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2592 if(!pProto)
2594 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2595 return;
2598 uint32 num_to_add;
2600 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2601 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2603 int32 basePoints = m_currentBasePoints[i];
2604 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2605 if (randomPoints)
2606 num_to_add = basePoints + irand(1, randomPoints);
2607 else
2608 num_to_add = basePoints + 1;
2610 else if (pProto->MaxCount == 1)
2611 num_to_add = 1;
2612 else if(player->getLevel() >= m_spellInfo->spellLevel)
2614 int32 basePoints = m_currentBasePoints[i];
2615 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2616 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2618 else
2619 num_to_add = 2;
2621 if (num_to_add < 1)
2622 num_to_add = 1;
2623 if (num_to_add > pProto->GetMaxStackSize())
2624 num_to_add = pProto->GetMaxStackSize();
2626 // init items_count to 1, since 1 item will be created regardless of specialization
2627 int items_count=1;
2628 // the chance to create additional items
2629 float additionalCreateChance=0.0f;
2630 // the maximum number of created additional items
2631 uint8 additionalMaxNum=0;
2632 // get the chance and maximum number for creating extra items
2633 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2635 // roll with this chance till we roll not to create or we create the max num
2636 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2637 ++items_count;
2640 // really will be created more items
2641 num_to_add *= items_count;
2643 // can the player store the new item?
2644 ItemPosCountVec dest;
2645 uint32 no_space = 0;
2646 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2647 if( msg != EQUIP_ERR_OK )
2649 // convert to possible store amount
2650 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2651 num_to_add -= no_space;
2652 else
2654 // if not created by another reason from full inventory or unique items amount limitation
2655 player->SendEquipError( msg, NULL, NULL );
2656 return;
2660 if(num_to_add)
2662 // create the new item and store it
2663 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2665 // was it successful? return error if not
2666 if(!pItem)
2668 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2669 return;
2672 // set the "Crafted by ..." property of the item
2673 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2674 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2676 // send info to the client
2677 if(pItem)
2678 player->SendNewItem(pItem, num_to_add, true, true);
2680 // we succeeded in creating at least one item, so a levelup is possible
2681 player->UpdateCraftSkill(m_spellInfo->Id);
2684 // for battleground marks send by mail if not add all expected
2685 if(no_space > 0 )
2687 BattleGroundTypeId bgType;
2688 switch(m_spellInfo->Id)
2690 case SPELL_AV_MARK_WINNER:
2691 case SPELL_AV_MARK_LOSER:
2692 bgType = BATTLEGROUND_AV;
2693 break;
2694 case SPELL_WS_MARK_WINNER:
2695 case SPELL_WS_MARK_LOSER:
2696 bgType = BATTLEGROUND_WS;
2697 break;
2698 case SPELL_AB_MARK_WINNER:
2699 case SPELL_AB_MARK_LOSER:
2700 bgType = BATTLEGROUND_AB;
2701 break;
2702 default:
2703 return;
2706 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2707 bg->SendRewardMarkByMail(player,newitemid,no_space);
2711 void Spell::EffectCreateItem(uint32 i)
2713 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2716 void Spell::EffectCreateItem2(uint32 i)
2718 // special case: generate using spell_loot_template
2719 if(!m_spellInfo->EffectItemType[i])
2721 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
2722 return;
2724 // create some random items
2725 ((Player*)m_caster)->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
2726 return;
2728 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2731 void Spell::EffectPersistentAA(uint32 i)
2733 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2735 if(Player* modOwner = m_caster->GetSpellModOwner())
2736 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2738 int32 duration = GetSpellDuration(m_spellInfo);
2739 DynamicObject* dynObj = new DynamicObject;
2740 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))
2742 delete dynObj;
2743 return;
2745 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2746 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2747 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2748 m_caster->AddDynObject(dynObj);
2749 dynObj->GetMap()->Add(dynObj);
2752 void Spell::EffectEnergize(uint32 i)
2754 if(!unitTarget)
2755 return;
2756 if(!unitTarget->isAlive())
2757 return;
2759 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2760 return;
2762 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2764 // Some level depends spells
2765 int multiplier = 0;
2766 int level_diff = 0;
2767 switch (m_spellInfo->Id)
2769 // Restore Energy
2770 case 9512:
2771 level_diff = m_caster->getLevel() - 40;
2772 multiplier = 2;
2773 break;
2774 // Blood Fury
2775 case 24571:
2776 level_diff = m_caster->getLevel() - 60;
2777 multiplier = 10;
2778 break;
2779 // Burst of Energy
2780 case 24532:
2781 level_diff = m_caster->getLevel() - 60;
2782 multiplier = 4;
2783 break;
2784 default:
2785 break;
2788 if (level_diff > 0)
2789 damage -= multiplier * level_diff;
2791 if(damage < 0)
2792 return;
2794 if(unitTarget->GetMaxPower(power) == 0)
2795 return;
2797 unitTarget->ModifyPower(power,damage);
2798 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2800 // Mad Alchemist's Potion
2801 if (m_spellInfo->Id == 45051)
2803 // find elixirs on target
2804 uint32 elixir_mask = 0;
2805 Unit::AuraMap& Auras = unitTarget->GetAuras();
2806 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2808 uint32 spell_id = itr->second->GetId();
2809 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2810 elixir_mask |= mask;
2813 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2814 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2816 // get all available elixirs by mask and spell level
2817 std::vector<uint32> elixirs;
2818 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2819 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2821 if (itr->second & elixir_mask)
2823 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2824 continue;
2826 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2827 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2828 continue;
2830 elixirs.push_back(itr->first);
2834 if (!elixirs.empty())
2836 // cast random elixir on target
2837 uint32 rand_spell = urand(0,elixirs.size()-1);
2838 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2843 void Spell::EffectEnergisePct(uint32 i)
2845 if(!unitTarget)
2846 return;
2847 if(!unitTarget->isAlive())
2848 return;
2850 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2851 return;
2853 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2855 uint32 maxPower = unitTarget->GetMaxPower(power);
2856 if(maxPower == 0)
2857 return;
2859 uint32 gain = damage * maxPower / 100;
2860 unitTarget->ModifyPower(power, gain);
2861 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2864 void Spell::SendLoot(uint64 guid, LootType loottype)
2866 Player* player = (Player*)m_caster;
2867 if (!player)
2868 return;
2870 if (gameObjTarget)
2872 if (Script->GOHello(player, gameObjTarget))
2873 return;
2875 switch (gameObjTarget->GetGoType())
2877 case GAMEOBJECT_TYPE_DOOR:
2878 case GAMEOBJECT_TYPE_BUTTON:
2879 gameObjTarget->UseDoorOrButton();
2880 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2881 return;
2883 case GAMEOBJECT_TYPE_QUESTGIVER:
2884 // start or end quest
2885 player->PrepareQuestMenu(guid);
2886 player->SendPreparedQuest(guid);
2887 return;
2889 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2890 // triggering linked GO
2891 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2892 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2893 return;
2895 case GAMEOBJECT_TYPE_GOOBER:
2896 // goober_scripts can be triggered if the player don't have the quest
2897 if (gameObjTarget->GetGOInfo()->goober.eventId)
2899 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2900 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2903 // cast goober spell
2904 if (gameObjTarget->GetGOInfo()->goober.questId)
2905 ///Quest require to be active for GO using
2906 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2907 return;
2909 gameObjTarget->AddUniqueUse(player);
2910 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2912 //TODO? Objective counting called without spell check but with quest objective check
2913 // if send spell id then this line will duplicate to spell casting call (double counting)
2914 // So we or have this line and not required in quest_template have reqSpellIdN
2915 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2916 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2918 // triggering linked GO
2919 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2920 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2922 return;
2924 case GAMEOBJECT_TYPE_CHEST:
2925 // TODO: possible must be moved to loot release (in different from linked triggering)
2926 if (gameObjTarget->GetGOInfo()->chest.eventId)
2928 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2929 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2932 // triggering linked GO
2933 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2934 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2936 // Don't return, let loots been taken
2937 default:
2938 break;
2942 // Send loot
2943 player->SendLoot(guid, loottype);
2946 void Spell::EffectOpenLock(uint32 effIndex)
2948 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2950 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2951 return;
2954 Player* player = (Player*)m_caster;
2956 uint32 lockId = 0;
2957 uint64 guid = 0;
2959 // Get lockId
2960 if(gameObjTarget)
2962 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2963 // Arathi Basin banner opening !
2964 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2965 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2967 //CanUseBattleGroundObject() already called in CheckCast()
2968 // in battleground check
2969 if(BattleGround *bg = player->GetBattleGround())
2971 // check if it's correct bg
2972 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2973 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2974 return;
2977 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2979 //CanUseBattleGroundObject() already called in CheckCast()
2980 // in battleground check
2981 if(BattleGround *bg = player->GetBattleGround())
2983 if(bg->GetTypeID() == BATTLEGROUND_EY)
2984 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2985 return;
2988 lockId = gameObjTarget->GetLockId();
2989 guid = gameObjTarget->GetGUID();
2991 else if(itemTarget)
2993 lockId = itemTarget->GetProto()->LockID;
2994 guid = itemTarget->GetGUID();
2996 else
2998 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2999 return;
3002 SkillType skillId = SKILL_NONE;
3003 int32 reqSkillValue = 0;
3004 int32 skillValue;
3006 SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue);
3007 if(res != SPELL_CAST_OK)
3009 SendCastResult(res);
3010 return;
3013 SendLoot(guid, LOOT_SKINNING);
3015 // not allow use skill grow at item base open
3016 if(!m_CastItem && skillId != SKILL_NONE)
3018 // update skill if really known
3019 if(uint32 pureSkillValue = player->GetPureSkillValue(skillId))
3021 if(gameObjTarget)
3023 // Allow one skill-up until respawned
3024 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3025 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) )
3026 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3028 else if(itemTarget)
3030 // Do one skill-up
3031 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
3037 void Spell::EffectSummonChangeItem(uint32 i)
3039 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3040 return;
3042 Player *player = (Player*)m_caster;
3044 // applied only to using item
3045 if(!m_CastItem)
3046 return;
3048 // ... only to item in own inventory/bank/equip_slot
3049 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3050 return;
3052 uint32 newitemid = m_spellInfo->EffectItemType[i];
3053 if(!newitemid)
3054 return;
3056 uint16 pos = m_CastItem->GetPos();
3058 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3059 if( !pNewItem )
3060 return;
3062 for(uint8 j= PERM_ENCHANTMENT_SLOT; j<=TEMP_ENCHANTMENT_SLOT; ++j)
3064 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(j)))
3065 pNewItem->SetEnchantment(EnchantmentSlot(j), m_CastItem->GetEnchantmentId(EnchantmentSlot(j)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(j)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(j)));
3068 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3070 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3071 player->DurabilityLoss(pNewItem, loosePercent);
3074 if( player->IsInventoryPos( pos ) )
3076 ItemPosCountVec dest;
3077 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3078 if( msg == EQUIP_ERR_OK )
3080 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3082 // prevent crash at access and unexpected charges counting with item update queue corrupt
3083 if(m_CastItem==m_targets.getItemTarget())
3084 m_targets.setItemTarget(NULL);
3086 m_CastItem = NULL;
3088 player->StoreItem( dest, pNewItem, true);
3089 return;
3092 else if( player->IsBankPos ( pos ) )
3094 ItemPosCountVec dest;
3095 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3096 if( msg == EQUIP_ERR_OK )
3098 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3100 // prevent crash at access and unexpected charges counting with item update queue corrupt
3101 if(m_CastItem==m_targets.getItemTarget())
3102 m_targets.setItemTarget(NULL);
3104 m_CastItem = NULL;
3106 player->BankItem( dest, pNewItem, true);
3107 return;
3110 else if( player->IsEquipmentPos ( pos ) )
3112 uint16 dest;
3113 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3114 if( msg == EQUIP_ERR_OK )
3116 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3118 // prevent crash at access and unexpected charges counting with item update queue corrupt
3119 if(m_CastItem==m_targets.getItemTarget())
3120 m_targets.setItemTarget(NULL);
3122 m_CastItem = NULL;
3124 player->EquipItem( dest, pNewItem, true);
3125 player->AutoUnequipOffhandIfNeed();
3126 return;
3130 // fail
3131 delete pNewItem;
3134 void Spell::EffectOpenSecretSafe(uint32 i)
3136 EffectOpenLock(i); //no difference for now
3139 void Spell::EffectProficiency(uint32 /*i*/)
3141 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3142 return;
3143 Player *p_target = (Player*)unitTarget;
3145 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3146 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3148 p_target->AddWeaponProficiency(subClassMask);
3149 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3151 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3153 p_target->AddArmorProficiency(subClassMask);
3154 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3158 void Spell::EffectApplyAreaAura(uint32 i)
3160 if(!unitTarget)
3161 return;
3162 if(!unitTarget->isAlive())
3163 return;
3165 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3166 unitTarget->AddAura(Aur);
3169 void Spell::EffectSummonType(uint32 i)
3171 switch(m_spellInfo->EffectMiscValueB[i])
3173 case SUMMON_TYPE_GUARDIAN:
3174 case SUMMON_TYPE_POSESSED:
3175 case SUMMON_TYPE_POSESSED2:
3176 case SUMMON_TYPE_FORCE_OF_NATURE:
3177 case SUMMON_TYPE_GUARDIAN2:
3178 EffectSummonGuardian(i);
3179 break;
3180 case SUMMON_TYPE_WILD:
3181 EffectSummonWild(i);
3182 break;
3183 case SUMMON_TYPE_DEMON:
3184 EffectSummonDemon(i);
3185 break;
3186 case SUMMON_TYPE_SUMMON:
3187 EffectSummon(i);
3188 break;
3189 case SUMMON_TYPE_CRITTER:
3190 case SUMMON_TYPE_CRITTER2:
3191 case SUMMON_TYPE_CRITTER3:
3192 EffectSummonCritter(i);
3193 break;
3194 case SUMMON_TYPE_TOTEM_SLOT1:
3195 case SUMMON_TYPE_TOTEM_SLOT2:
3196 case SUMMON_TYPE_TOTEM_SLOT3:
3197 case SUMMON_TYPE_TOTEM_SLOT4:
3198 case SUMMON_TYPE_TOTEM:
3199 EffectSummonTotem(i);
3200 break;
3201 case SUMMON_TYPE_UNKNOWN1:
3202 case SUMMON_TYPE_UNKNOWN2:
3203 case SUMMON_TYPE_UNKNOWN3:
3204 case SUMMON_TYPE_UNKNOWN4:
3205 case SUMMON_TYPE_UNKNOWN5:
3206 break;
3207 default:
3208 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3209 break;
3213 void Spell::EffectSummon(uint32 i)
3215 if(m_caster->GetPetGUID())
3216 return;
3218 if(!unitTarget)
3219 return;
3220 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3221 if(!pet_entry)
3222 return;
3223 uint32 level = m_caster->getLevel();
3224 Pet* spawnCreature = new Pet(SUMMON_PET);
3226 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3228 // set timer for unsummon
3229 int32 duration = GetSpellDuration(m_spellInfo);
3230 if(duration > 0)
3231 spawnCreature->SetDuration(duration);
3233 return;
3236 Map *map = m_caster->GetMap();
3237 uint32 pet_number = objmgr.GeneratePetNumber();
3238 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_caster->GetPhaseMask(),
3239 m_spellInfo->EffectMiscValue[i], pet_number))
3241 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3242 delete spawnCreature;
3243 return;
3246 // Summon in dest location
3247 float x,y,z;
3248 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3250 x = m_targets.m_destX;
3251 y = m_targets.m_destY;
3252 z = m_targets.m_destZ;
3254 else
3255 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3257 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3259 if(!spawnCreature->IsPositionValid())
3261 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3262 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3263 delete spawnCreature;
3264 return;
3267 // set timer for unsummon
3268 int32 duration = GetSpellDuration(m_spellInfo);
3269 if(duration > 0)
3270 spawnCreature->SetDuration(duration);
3272 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3273 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3274 spawnCreature->setPowerType(POWER_MANA);
3275 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3276 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3277 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3278 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3279 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3280 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3281 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3282 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3283 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3285 spawnCreature->InitStatsForLevel(level);
3287 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3289 spawnCreature->AIM_Initialize();
3290 spawnCreature->InitPetCreateSpells();
3291 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3292 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3294 std::string name = m_caster->GetName();
3295 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3296 spawnCreature->SetName( name );
3298 map->Add((Creature*)spawnCreature);
3300 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3302 m_caster->SetPet(spawnCreature);
3303 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3304 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3305 ((Player*)m_caster)->PetSpellInitialize();
3309 void Spell::EffectLearnSpell(uint32 i)
3311 if(!unitTarget)
3312 return;
3314 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3316 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3317 EffectLearnPetSpell(i);
3319 return;
3322 Player *player = (Player*)unitTarget;
3324 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3325 player->learnSpell(spellToLearn,false);
3327 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3330 void Spell::EffectDispel(uint32 i)
3332 if(!unitTarget)
3333 return;
3335 // Fill possible dispell list
3336 std::vector <Aura *> dispel_list;
3338 // Create dispel mask by dispel type
3339 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3340 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3341 Unit::AuraMap const& auras = unitTarget->GetAuras();
3342 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3344 Aura *aur = (*itr).second;
3345 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3347 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3349 bool positive = true;
3350 if (!aur->IsPositive())
3351 positive = false;
3352 else
3353 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3355 // do not remove positive auras if friendly target
3356 // negative auras if non-friendly target
3357 if(positive == unitTarget->IsFriendlyTo(m_caster))
3358 continue;
3360 // Add aura to dispel list
3361 dispel_list.push_back(aur);
3364 // Ok if exist some buffs for dispel try dispel it
3365 if (!dispel_list.empty())
3367 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3368 std::list < uint32 > fail_list; // spell_id
3369 int32 list_size = dispel_list.size();
3370 // Dispell N = damage buffs (or while exist buffs for dispel)
3371 for (int32 count=0; count < damage && list_size > 0; ++count)
3373 // Random select buff for dispel
3374 Aura *aur = dispel_list[urand(0, list_size-1)];
3376 SpellEntry const* spellInfo = aur->GetSpellProto();
3377 // Base dispel chance
3378 // TODO: possible chance depend from spell level??
3379 int32 miss_chance = 0;
3380 // Apply dispel mod from aura caster
3381 if (Unit *caster = aur->GetCaster())
3383 if ( Player* modOwner = caster->GetSpellModOwner() )
3384 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3386 // Try dispel
3387 if (roll_chance_i(miss_chance))
3388 fail_list.push_back(aur->GetId());
3389 else
3390 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3391 // Remove buff from list for prevent doubles
3392 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3394 Aura *dispeled = *j;
3395 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3397 j = dispel_list.erase(j);
3398 --list_size;
3400 else
3401 ++j;
3404 // Send success log and really remove auras
3405 if (!success_list.empty())
3407 int32 count = success_list.size();
3408 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3409 data.append(unitTarget->GetPackGUID()); // Victim GUID
3410 data.append(m_caster->GetPackGUID()); // Caster GUID
3411 data << uint32(m_spellInfo->Id); // Dispell spell id
3412 data << uint8(0); // not used
3413 data << uint32(count); // count
3414 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3416 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3417 data << uint32(spellInfo->Id); // Spell Id
3418 data << uint8(0); // 0 - dispeled !=0 cleansed
3419 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3421 m_caster->SendMessageToSet(&data, true);
3423 // On succes dispel
3424 // Devour Magic
3425 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
3427 uint32 heal_spell = 0;
3428 switch (m_spellInfo->Id)
3430 case 19505: heal_spell = 19658; break;
3431 case 19731: heal_spell = 19732; break;
3432 case 19734: heal_spell = 19733; break;
3433 case 19736: heal_spell = 19735; break;
3434 case 27276: heal_spell = 27278; break;
3435 case 27277: heal_spell = 27279; break;
3436 default:
3437 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3438 break;
3440 if (heal_spell)
3441 m_caster->CastSpell(m_caster, heal_spell, true);
3444 // Send fail log to client
3445 if (!fail_list.empty())
3447 // Failed to dispell
3448 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3449 data << uint64(m_caster->GetGUID()); // Caster GUID
3450 data << uint64(unitTarget->GetGUID()); // Victim GUID
3451 data << uint32(m_spellInfo->Id); // Dispell spell id
3452 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3453 data << uint32(*j); // Spell Id
3454 m_caster->SendMessageToSet(&data, true);
3459 void Spell::EffectDualWield(uint32 /*i*/)
3461 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3462 ((Player*)unitTarget)->SetCanDualWield(true);
3465 void Spell::EffectPull(uint32 /*i*/)
3467 // TODO: create a proper pull towards distract spell center for distract
3468 sLog.outDebug("WORLD: Spell Effect DUMMY");
3471 void Spell::EffectDistract(uint32 /*i*/)
3473 // Check for possible target
3474 if (!unitTarget || unitTarget->isInCombat())
3475 return;
3477 // target must be OK to do this
3478 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3479 return;
3481 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3483 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3485 // For players just turn them
3486 WorldPacket data;
3487 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3488 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3489 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3491 else
3493 // Set creature Distracted, Stop it, And turn it
3494 unitTarget->SetOrientation(angle);
3495 unitTarget->StopMoving();
3496 unitTarget->GetMotionMaster()->MoveDistract(damage*IN_MILISECONDS);
3500 void Spell::EffectPickPocket(uint32 /*i*/)
3502 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3503 return;
3505 // victim must be creature and attackable
3506 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3507 return;
3509 // victim have to be alive and humanoid or undead
3510 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3512 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3514 if (chance > irand(0, 19))
3516 // Stealing successful
3517 //sLog.outDebug("Sending loot from pickpocket");
3518 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3520 else
3522 // Reveal action + get attack
3523 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3524 if (((Creature*)unitTarget)->AI())
3525 ((Creature*)unitTarget)->AI()->AttackedBy(m_caster);
3530 void Spell::EffectAddFarsight(uint32 i)
3532 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3533 int32 duration = GetSpellDuration(m_spellInfo);
3534 DynamicObject* dynObj = new DynamicObject;
3535 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))
3537 delete dynObj;
3538 return;
3540 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3541 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3542 m_caster->AddDynObject(dynObj);
3543 dynObj->GetMap()->Add(dynObj);
3544 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3545 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3548 void Spell::EffectSummonWild(uint32 i)
3550 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3551 if(!creature_entry)
3552 return;
3554 uint32 level = m_caster->getLevel();
3556 // level of creature summoned using engineering item based at engineering skill level
3557 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3559 ItemPrototype const *proto = m_CastItem->GetProto();
3560 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3562 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3563 if(skill202)
3565 level = skill202/5;
3570 // select center of summon position
3571 float center_x = m_targets.m_destX;
3572 float center_y = m_targets.m_destY;
3573 float center_z = m_targets.m_destZ;
3575 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3577 int32 amount = damage > 0 ? damage : 1;
3579 for(int32 count = 0; count < amount; ++count)
3581 float px, py, pz;
3582 // If dest location if present
3583 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3585 // Summon 1 unit in dest location
3586 if (count == 0)
3588 px = m_targets.m_destX;
3589 py = m_targets.m_destY;
3590 pz = m_targets.m_destZ;
3592 // Summon in random point all other units if location present
3593 else
3594 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3596 // Summon if dest location not present near caster
3597 else
3598 m_caster->GetClosePoint(px,py,pz,3.0f);
3600 int32 duration = GetSpellDuration(m_spellInfo);
3602 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3604 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3608 void Spell::EffectSummonGuardian(uint32 i)
3610 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3611 if(!pet_entry)
3612 return;
3614 // Jewelery statue case (totem like)
3615 if(m_spellInfo->SpellIconID==2056)
3617 EffectSummonTotem(i);
3618 return;
3621 // set timer for unsummon
3622 int32 duration = GetSpellDuration(m_spellInfo);
3624 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3625 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3626 // so this code hack in fact
3627 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3628 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3629 return; // find old guardian, ignore summon
3631 // in another case summon new
3632 uint32 level = m_caster->getLevel();
3634 // level of pet summoned using engineering item based at engineering skill level
3635 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3637 ItemPrototype const *proto = m_CastItem->GetProto();
3638 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3640 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3641 if(skill202)
3643 level = skill202/5;
3648 // select center of summon position
3649 float center_x = m_targets.m_destX;
3650 float center_y = m_targets.m_destY;
3651 float center_z = m_targets.m_destZ;
3653 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3655 int32 amount = damage > 0 ? damage : 1;
3657 for(int32 count = 0; count < amount; ++count)
3659 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3661 Map *map = m_caster->GetMap();
3662 uint32 pet_number = objmgr.GeneratePetNumber();
3663 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_caster->GetPhaseMask(),
3664 m_spellInfo->EffectMiscValue[i], pet_number))
3666 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3667 delete spawnCreature;
3668 return;
3671 float px, py, pz;
3672 // If dest location if present
3673 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3675 // Summon 1 unit in dest location
3676 if (count == 0)
3678 px = m_targets.m_destX;
3679 py = m_targets.m_destY;
3680 pz = m_targets.m_destZ;
3682 // Summon in random point all other units if location present
3683 else
3684 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3686 // Summon if dest location not present near caster
3687 else
3688 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3690 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3692 if(!spawnCreature->IsPositionValid())
3694 sLog.outError("Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3695 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3696 delete spawnCreature;
3697 return;
3700 if(duration > 0)
3701 spawnCreature->SetDuration(duration);
3703 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3704 spawnCreature->setPowerType(POWER_MANA);
3705 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3706 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3707 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3708 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3709 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3710 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3711 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3713 spawnCreature->InitStatsForLevel(level);
3714 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3716 spawnCreature->AIM_Initialize();
3718 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3719 ((Player*)m_caster)->AddGuardian(spawnCreature);
3721 map->Add((Creature*)spawnCreature);
3725 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3727 if(!unitTarget)
3728 return;
3730 if(unitTarget->isInFlight())
3731 return;
3733 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3735 float fx,fy,fz;
3736 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3738 unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster);
3741 void Spell::EffectLearnSkill(uint32 i)
3743 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3744 return;
3746 if(damage < 0)
3747 return;
3749 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3750 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3751 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3754 void Spell::EffectAddHonor(uint32 /*i*/)
3756 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3757 return;
3759 // not scale value for item based reward (/10 value expected)
3760 if(m_CastItem)
3762 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10);
3763 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow());
3764 return;
3767 // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
3768 if( damage <= 50)
3770 uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
3771 ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward);
3772 sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
3774 else
3776 //maybe we have correct honor_gain in damage already
3777 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3778 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3782 void Spell::EffectTradeSkill(uint32 /*i*/)
3784 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3785 return;
3786 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3787 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3788 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3791 void Spell::EffectEnchantItemPerm(uint32 effect_idx)
3793 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3794 return;
3795 if (!itemTarget)
3796 return;
3798 Player* p_caster = (Player*)m_caster;
3800 // not grow at item use at item case
3801 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3803 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3804 if (!enchant_id)
3805 return;
3807 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3808 if(!pEnchant)
3809 return;
3811 // item can be in trade slot and have owner diff. from caster
3812 Player* item_owner = itemTarget->GetOwner();
3813 if(!item_owner)
3814 return;
3816 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3818 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3819 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3820 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3821 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3824 // remove old enchanting before applying new if equipped
3825 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3827 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3829 // add new enchanting if equipped
3830 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3833 void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
3835 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3836 return;
3837 if (!itemTarget)
3838 return;
3840 Player* p_caster = (Player*)m_caster;
3842 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3843 if (!enchant_id)
3844 return;
3846 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3847 if(!pEnchant)
3848 return;
3850 // support only enchantings with add socket in this slot
3852 bool add_socket = false;
3853 for(int i = 0; i < 3; ++i)
3855 if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
3857 add_socket = true;
3858 break;
3861 if(!add_socket)
3863 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.",
3864 m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
3865 return;
3869 // item can be in trade slot and have owner diff. from caster
3870 Player* item_owner = itemTarget->GetOwner();
3871 if(!item_owner)
3872 return;
3874 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3876 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3877 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3878 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3879 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3882 // remove old enchanting before applying new if equipped
3883 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
3885 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3887 // add new enchanting if equipped
3888 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
3891 void Spell::EffectEnchantItemTmp(uint32 i)
3893 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3894 return;
3896 Player* p_caster = (Player*)m_caster;
3898 if(!itemTarget)
3899 return;
3901 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3903 // Shaman Rockbiter Weapon
3904 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3906 int32 enchnting_damage = m_currentBasePoints[1]+1;
3908 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3909 // with already applied percent bonus from Elemental Weapons talent
3910 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3911 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3912 switch(enchnting_damage)
3914 // Rank 1
3915 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3916 // Rank 2
3917 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3918 case 5: enchant_id = 3025; break; // 20%
3919 // Rank 3
3920 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3921 case 7: enchant_id = 3027; break; // 20%
3922 // Rank 4
3923 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3924 case 10: enchant_id = 503; break; // 14%
3925 case 11: enchant_id = 3031; break; // 20%
3926 // Rank 5
3927 case 15: enchant_id = 3035; break; // 0%
3928 case 16: enchant_id = 1663; break; // 7%
3929 case 17: enchant_id = 3033; break; // 14%
3930 case 18: enchant_id = 3034; break; // 20%
3931 // Rank 6
3932 case 28: enchant_id = 3038; break; // 0%
3933 case 29: enchant_id = 683; break; // 7%
3934 case 31: enchant_id = 3036; break; // 14%
3935 case 33: enchant_id = 3037; break; // 20%
3936 // Rank 7
3937 case 40: enchant_id = 3041; break; // 0%
3938 case 42: enchant_id = 1664; break; // 7%
3939 case 45: enchant_id = 3039; break; // 14%
3940 case 48: enchant_id = 3040; break; // 20%
3941 // Rank 8
3942 case 49: enchant_id = 3044; break; // 0%
3943 case 52: enchant_id = 2632; break; // 7%
3944 case 55: enchant_id = 3042; break; // 14%
3945 case 58: enchant_id = 3043; break; // 20%
3946 // Rank 9
3947 case 62: enchant_id = 2633; break; // 0%
3948 case 66: enchant_id = 3018; break; // 7%
3949 case 70: enchant_id = 3019; break; // 14%
3950 case 74: enchant_id = 3020; break; // 20%
3951 default:
3952 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3953 return;
3957 if (!enchant_id)
3959 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3960 return;
3963 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3964 if(!pEnchant)
3966 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3967 return;
3970 // select enchantment duration
3971 uint32 duration;
3973 // rogue family enchantments exception by duration
3974 if(m_spellInfo->Id==38615)
3975 duration = 1800; // 30 mins
3976 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3977 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3978 duration = 3600; // 1 hour
3979 // shaman family enchantments
3980 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3981 duration = 1800; // 30 mins
3982 // other cases with this SpellVisual already selected
3983 else if(m_spellInfo->SpellVisual[0]==215)
3984 duration = 1800; // 30 mins
3985 // some fishing pole bonuses
3986 else if(m_spellInfo->SpellVisual[0]==563)
3987 duration = 600; // 10 mins
3988 // shaman rockbiter enchantments
3989 else if(m_spellInfo->SpellVisual[0]==0)
3990 duration = 1800; // 30 mins
3991 else if(m_spellInfo->Id==29702)
3992 duration = 300; // 5 mins
3993 else if(m_spellInfo->Id==37360)
3994 duration = 300; // 5 mins
3995 // default case
3996 else
3997 duration = 3600; // 1 hour
3999 // item can be in trade slot and have owner diff. from caster
4000 Player* item_owner = itemTarget->GetOwner();
4001 if(!item_owner)
4002 return;
4004 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
4006 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
4007 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
4008 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
4009 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
4012 // remove old enchanting before applying new if equipped
4013 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
4015 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
4017 // add new enchanting if equipped
4018 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
4021 void Spell::EffectTameCreature(uint32 /*i*/)
4023 if(m_caster->GetPetGUID())
4024 return;
4026 if(!unitTarget)
4027 return;
4029 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
4030 return;
4032 Creature* creatureTarget = (Creature*)unitTarget;
4034 if(creatureTarget->isPet())
4035 return;
4037 if(m_caster->getClass() != CLASS_HUNTER)
4038 return;
4040 // cast finish successfully
4041 //SendChannelUpdate(0);
4042 finish();
4044 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
4046 // kill original creature
4047 creatureTarget->setDeathState(JUST_DIED);
4048 creatureTarget->RemoveCorpse();
4049 creatureTarget->SetHealth(0); // just for nice GM-mode view
4051 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4053 // prepare visual effect for levelup
4054 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4056 // add to world
4057 pet->GetMap()->Add((Creature*)pet);
4059 // visual effect for levelup
4060 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4062 // caster have pet now
4063 m_caster->SetPet(pet);
4065 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4067 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4068 ((Player*)m_caster)->PetSpellInitialize();
4072 void Spell::EffectSummonPet(uint32 i)
4074 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4076 Pet *OldSummon = m_caster->GetPet();
4078 // if pet requested type already exist
4079 if( OldSummon )
4081 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4083 // pet in corpse state can't be summoned
4084 if( OldSummon->isDead() )
4085 return;
4087 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4088 OldSummon->SetMapId(m_caster->GetMapId());
4090 float px, py, pz;
4091 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4093 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4094 m_caster->GetMap()->Add((Creature*)OldSummon);
4096 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4098 ((Player*)m_caster)->PetSpellInitialize();
4100 return;
4103 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4104 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4105 else
4106 return;
4109 Pet* NewSummon = new Pet;
4111 // petentry==0 for hunter "call pet" (current pet summoned if any)
4112 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4114 if(NewSummon->getPetType()==SUMMON_PET)
4116 // Remove Demonic Sacrifice auras (known pet)
4117 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4118 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4120 if((*itr)->GetModifier()->m_miscvalue==2228)
4122 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4123 itr = auraClassScripts.begin();
4125 else
4126 ++itr;
4130 return;
4133 // not error in case fail hunter call pet
4134 if(!petentry)
4136 delete NewSummon;
4137 return;
4140 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4142 if(!cInfo)
4144 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4145 delete NewSummon;
4146 return;
4149 Map *map = m_caster->GetMap();
4150 uint32 pet_number = objmgr.GeneratePetNumber();
4151 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
4152 petentry, pet_number))
4154 delete NewSummon;
4155 return;
4158 float px, py, pz;
4159 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4161 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4163 if(!NewSummon->IsPositionValid())
4165 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4166 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4167 delete NewSummon;
4168 return;
4171 uint32 petlevel = m_caster->getLevel();
4172 NewSummon->setPetType(SUMMON_PET);
4174 uint32 faction = m_caster->getFaction();
4175 if(m_caster->GetTypeId() == TYPEID_UNIT)
4177 if ( ((Creature*)m_caster)->isTotem() )
4178 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4179 else
4180 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4183 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4184 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4185 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4186 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4187 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4188 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4189 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4190 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4191 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4192 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4194 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4195 // this enables pet details window (Shift+P)
4197 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4198 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4199 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4201 NewSummon->InitStatsForLevel(petlevel);
4202 NewSummon->InitPetCreateSpells();
4203 NewSummon->InitTalentForLevel();
4205 if(NewSummon->getPetType()==SUMMON_PET)
4207 // Remove Demonic Sacrifice auras (new pet)
4208 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4209 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4211 if((*itr)->GetModifier()->m_miscvalue==2228)
4213 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4214 itr = auraClassScripts.begin();
4216 else
4217 ++itr;
4220 // generate new name for summon pet
4221 std::string new_name=objmgr.GeneratePetName(petentry);
4222 if(!new_name.empty())
4223 NewSummon->SetName(new_name);
4225 else if(NewSummon->getPetType()==HUNTER_PET)
4226 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4228 NewSummon->AIM_Initialize();
4229 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4230 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4232 map->Add((Creature*)NewSummon);
4234 m_caster->SetPet(NewSummon);
4235 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4237 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4239 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4240 ((Player*)m_caster)->PetSpellInitialize();
4244 void Spell::EffectLearnPetSpell(uint32 i)
4246 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4247 return;
4249 Player *_player = (Player*)m_caster;
4251 Pet *pet = _player->GetPet();
4252 if(!pet)
4253 return;
4254 if(!pet->isAlive())
4255 return;
4257 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4258 if(!learn_spellproto)
4259 return;
4261 pet->learnSpell(learn_spellproto->Id);
4263 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4264 _player->PetSpellInitialize();
4267 void Spell::EffectTaunt(uint32 /*i*/)
4269 if (!unitTarget)
4270 return;
4272 // this effect use before aura Taunt apply for prevent taunt already attacking target
4273 // for spell as marked "non effective at already attacking target"
4274 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
4276 if (unitTarget->getVictim()==m_caster)
4278 SendCastResult(SPELL_FAILED_DONT_REPORT);
4279 return;
4283 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4284 if (unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4285 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4288 void Spell::EffectWeaponDmg(uint32 i)
4290 if(!unitTarget)
4291 return;
4292 if(!unitTarget->isAlive())
4293 return;
4295 // multiple weapon dmg effect workaround
4296 // execute only the last weapon damage
4297 // and handle all effects at once
4298 for (int j = 0; j < 3; j++)
4300 switch(m_spellInfo->Effect[j])
4302 case SPELL_EFFECT_WEAPON_DAMAGE:
4303 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4304 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4305 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4306 if (j < i) // we must calculate only at last weapon effect
4307 return;
4308 break;
4312 // some spell specific modifiers
4313 bool spellBonusNeedWeaponDamagePercentMod = false; // if set applied weapon damage percent mode to spell bonus
4315 float weaponDamagePercentMod = 1.0f; // applied to weapon damage and to fixed effect damage bonus
4316 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4317 bool normalized = false;
4319 int32 spell_bonus = 0; // bonus specific for spell
4320 switch(m_spellInfo->SpellFamilyName)
4322 case SPELLFAMILY_WARRIOR:
4324 // Whirlwind, single only spell with 2 weapon white damage apply if have
4325 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4327 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4328 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4330 // Devastate bonus and sunder armor refresh
4331 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4333 uint32 stack = 0;
4334 // Need refresh all Sunder Armor auras from this caster
4335 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4336 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4338 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4339 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4340 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4341 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4343 (*itr).second->RefreshAura();
4344 stack = (*itr).second->GetStackAmount();
4347 if (stack)
4348 spell_bonus += stack * CalculateDamage(2, unitTarget);
4350 break;
4352 case SPELLFAMILY_ROGUE:
4354 // Mutilate (for each hand)
4355 if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4357 bool found = false;
4358 // fast check
4359 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4360 found = true;
4361 // full aura scan
4362 else
4364 Unit::AuraMap const& auras = unitTarget->GetAuras();
4365 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4367 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4369 found = true;
4370 break;
4375 if(found)
4376 totalDamagePercentMod *= 1.2f; // 120% if poisoned
4378 break;
4380 case SPELLFAMILY_PALADIN:
4382 // Seal of Command - receive benefit from Spell Damage and Healing
4383 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4385 spellBonusNeedWeaponDamagePercentMod = true;// apply weaponDamagePercentMod to spell_bonus (and then to all bonus, fixes and weapon already have applied)
4386 spell_bonus += int32(0.23f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4387 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4389 break;
4391 case SPELLFAMILY_SHAMAN:
4393 // Skyshatter Harness item set bonus
4394 // Stormstrike
4395 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4397 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4398 for(Unit::AuraList::const_iterator citr = m_OverrideClassScript.begin(); citr != m_OverrideClassScript.end(); ++citr)
4400 // Stormstrike AP Buff
4401 if ( (*citr)->GetModifier()->m_miscvalue == 5634 )
4403 m_caster->CastSpell(m_caster,38430,true,NULL,*citr);
4404 break;
4411 int32 fixed_bonus = 0;
4412 for (int j = 0; j < 3; j++)
4414 switch(m_spellInfo->Effect[j])
4416 case SPELL_EFFECT_WEAPON_DAMAGE:
4417 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4418 fixed_bonus += CalculateDamage(j,unitTarget);
4419 break;
4420 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4421 fixed_bonus += CalculateDamage(j,unitTarget);
4422 normalized = true;
4423 break;
4424 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4425 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4427 // applied only to prev.effects fixed damage
4428 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4429 break;
4430 default:
4431 break; // not weapon damage effect, just skip
4435 // apply weaponDamagePercentMod to spell bonus also
4436 if(spellBonusNeedWeaponDamagePercentMod)
4437 spell_bonus = int32(spell_bonus*weaponDamagePercentMod);
4439 // non-weapon damage
4440 int32 bonus = spell_bonus + fixed_bonus;
4442 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4443 if(bonus)
4445 UnitMods unitMod;
4446 switch(m_attackType)
4448 default:
4449 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4450 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4451 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4454 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4455 bonus = int32(bonus*weapon_total_pct);
4458 // + weapon damage with applied weapon% dmg to base weapon damage in call
4459 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4461 // total damage
4462 bonus = int32(bonus*totalDamagePercentMod);
4464 // prevent negative damage
4465 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4467 // Add melee damage bonuses (also check for negative)
4468 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4469 m_damage+= eff_damage;
4471 // Hemorrhage
4472 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4474 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4475 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4478 // Mangle (Cat): CP
4479 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4481 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4482 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4485 // take ammo
4486 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4488 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4490 // wands don't have ammo
4491 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4492 return;
4494 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4496 if(pItem->GetMaxStackCount()==1)
4498 // decrease durability for non-stackable throw weapon
4499 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4501 else
4503 // decrease items amount for stackable throw weapon
4504 uint32 count = 1;
4505 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4508 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4509 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4513 void Spell::EffectThreat(uint32 /*i*/)
4515 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4516 return;
4518 if(!unitTarget->CanHaveThreatList())
4519 return;
4521 unitTarget->AddThreat(m_caster, float(damage));
4524 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4526 if(!unitTarget)
4527 return;
4528 if(!unitTarget->isAlive())
4529 return;
4531 uint32 heal = m_caster->GetMaxHealth();
4533 m_healing+=heal;
4536 void Spell::EffectInterruptCast(uint32 /*i*/)
4538 if(!unitTarget)
4539 return;
4540 if(!unitTarget->isAlive())
4541 return;
4543 // TODO: not all spells that used this effect apply cooldown at school spells
4544 // also exist case: apply cooldown to interrupted cast only and to all spells
4545 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4547 if (unitTarget->m_currentSpells[i])
4549 // check if we can interrupt spell
4550 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4552 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4553 unitTarget->InterruptSpell(i,false);
4559 void Spell::EffectSummonObjectWild(uint32 i)
4561 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4563 GameObject* pGameObj = new GameObject;
4565 WorldObject* target = focusObject;
4566 if( !target )
4567 target = m_caster;
4569 float x,y,z;
4570 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4572 x = m_targets.m_destX;
4573 y = m_targets.m_destY;
4574 z = m_targets.m_destZ;
4576 else
4577 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4579 Map *map = target->GetMap();
4581 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4582 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
4584 delete pGameObj;
4585 return;
4588 int32 duration = GetSpellDuration(m_spellInfo);
4589 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4590 pGameObj->SetSpellId(m_spellInfo->Id);
4592 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4593 m_caster->AddGameObject(pGameObj);
4594 map->Add(pGameObj);
4596 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4598 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4600 Player *pl = (Player*)m_caster;
4601 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4602 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4604 uint32 team = ALLIANCE;
4606 if(pl->GetTeam() == team)
4607 team = HORDE;
4609 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4614 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4616 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4618 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4619 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4621 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4626 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4628 GameObject* linkedGO = new GameObject;
4629 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4630 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
4632 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4633 linkedGO->SetSpellId(m_spellInfo->Id);
4635 m_caster->AddGameObject(linkedGO);
4636 map->Add(linkedGO);
4638 else
4640 delete linkedGO;
4641 linkedGO = NULL;
4642 return;
4647 void Spell::EffectScriptEffect(uint32 effIndex)
4649 // TODO: we must implement hunter pet summon at login there (spell 6962)
4651 switch(m_spellInfo->SpellFamilyName)
4653 case SPELLFAMILY_GENERIC:
4655 switch(m_spellInfo->Id)
4657 // PX-238 Winter Wondervolt TRAP
4658 case 26275:
4660 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4662 // check presence
4663 for(int j = 0; j < 4; ++j)
4664 if(unitTarget->HasAura(spells[j],0))
4665 return;
4667 // select spell
4668 uint32 iTmpSpellId = spells[urand(0,3)];
4670 // cast
4671 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4672 return;
4674 // Bending Shinbone
4675 case 8856:
4677 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4678 return;
4680 uint32 spell_id = 0;
4681 switch(urand(1,5))
4683 case 1: spell_id = 8854; break;
4684 default: spell_id = 8855; break;
4687 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4688 return;
4690 // Brittle Armor - need remove one 24575 Brittle Armor aura
4691 case 24590:
4692 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4693 return;
4694 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4695 case 26465:
4696 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4697 return;
4698 // Orb teleport spells
4699 case 25140:
4700 case 25143:
4701 case 25650:
4702 case 25652:
4703 case 29128:
4704 case 29129:
4705 case 35376:
4706 case 35727:
4708 if(!unitTarget)
4709 return;
4711 uint32 spellid;
4712 switch(m_spellInfo->Id)
4714 case 25140: spellid = 32571; break;
4715 case 25143: spellid = 32572; break;
4716 case 25650: spellid = 30140; break;
4717 case 25652: spellid = 30141; break;
4718 case 29128: spellid = 32568; break;
4719 case 29129: spellid = 32569; break;
4720 case 35376: spellid = 25649; break;
4721 case 35727: spellid = 35730; break;
4722 default:
4723 return;
4726 unitTarget->CastSpell(unitTarget,spellid,false);
4727 return;
4729 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4730 case 22539:
4731 case 22972:
4732 case 22975:
4733 case 22976:
4734 case 22977:
4735 case 22978:
4736 case 22979:
4737 case 22980:
4738 case 22981:
4739 case 22982:
4740 case 22983:
4741 case 22984:
4742 case 22985:
4744 if(!unitTarget || !unitTarget->isAlive())
4745 return;
4747 // Onyxia Scale Cloak
4748 if(unitTarget->GetDummyAura(22683))
4749 return;
4751 // Shadow Flame
4752 m_caster->CastSpell(unitTarget, 22682, true);
4753 return;
4755 // Summon Black Qiraji Battle Tank
4756 case 26656:
4758 if(!unitTarget)
4759 return;
4761 // Prevent stacking of mounts
4762 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4764 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4765 if (unitTarget->GetAreaId() == 3428)
4766 unitTarget->CastSpell(unitTarget, 25863, false);
4767 else
4768 unitTarget->CastSpell(unitTarget, 26655, false);
4769 return;
4771 // Piccolo of the Flaming Fire
4772 case 17512:
4774 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4775 return;
4776 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4777 return;
4779 // Escape artist
4780 case 20589:
4782 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4783 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
4784 return;
4786 // Mirren's Drinking Hat
4787 case 29830:
4789 uint32 item = 0;
4790 switch ( urand(1,6) )
4792 case 1:case 2:case 3:
4793 item = 23584;break; // Loch Modan Lager
4794 case 4:case 5:
4795 item = 23585;break; // Stouthammer Lite
4796 case 6:
4797 item = 23586;break; // Aerie Peak Pale Ale
4799 if (item)
4800 DoCreateItem(effIndex,item);
4801 break;
4803 // Improved Sprint
4804 case 30918:
4806 // Removes snares and roots.
4807 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4808 Unit::AuraMap& Auras = unitTarget->GetAuras();
4809 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4811 next = iter;
4812 ++next;
4813 Aura *aur = iter->second;
4814 if (!aur->IsPositive()) //only remove negative spells
4816 // check for mechanic mask
4817 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4819 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4820 if(Auras.empty())
4821 break;
4822 else
4823 next = Auras.begin();
4827 break;
4829 // Flame Crash
4830 case 41126:
4832 if(!unitTarget)
4833 return;
4835 unitTarget->CastSpell(unitTarget, 41131, true);
4836 break;
4838 // Force Cast - Portal Effect: Sunwell Isle
4839 case 44876:
4841 if(!unitTarget)
4842 return;
4844 unitTarget->CastSpell(unitTarget, 44870, true);
4845 break;
4847 // Goblin Weather Machine
4848 case 46203:
4850 if(!unitTarget)
4851 return;
4853 uint32 spellId = 0;
4854 switch(rand()%4)
4856 case 0: spellId = 46740; break;
4857 case 1: spellId = 46739; break;
4858 case 2: spellId = 46738; break;
4859 case 3: spellId = 46736; break;
4861 unitTarget->CastSpell(unitTarget, spellId, true);
4862 break;
4864 //5,000 Gold
4865 case 46642:
4867 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4868 return;
4870 ((Player*)unitTarget)->ModifyMoney(50000000);
4872 break;
4874 // Emblazon Runeblade
4875 case 51770:
4877 if(!unitTarget)
4878 return;
4880 unitTarget->CastSpell(unitTarget,51771,false);
4881 break;
4883 // Death Gate
4884 case 52751:
4886 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4887 return;
4888 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4889 unitTarget->CastSpell(unitTarget, damage, false);
4890 break;
4892 // Winged Steed of the Ebon Blade
4893 case 54729:
4895 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4896 return;
4898 // Prevent stacking of mounts
4899 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4901 // Triggered spell id dependent of riding skill
4902 if(uint16 skillval = ((Player*)unitTarget)->GetSkillValue(SKILL_RIDING))
4904 if (skillval >= 300)
4905 unitTarget->CastSpell(unitTarget, 54727, true);
4906 else
4907 unitTarget->CastSpell(unitTarget, 54726, true);
4909 return;
4911 case 58418: // Portal to Orgrimmar
4912 case 58420: // Portal to Stormwind
4914 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex!=0)
4915 return;
4917 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
4918 uint32 questID = m_spellInfo->CalculateSimpleValue(1);
4920 if (((Player*)unitTarget)->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !((Player*)unitTarget)->GetQuestRewardStatus (questID))
4921 unitTarget->CastSpell(unitTarget, spellID, true);
4923 return;
4925 case 59317: // Teleporting
4926 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4927 return;
4929 // return from top
4930 if (((Player*)unitTarget)->GetAreaId() == 4637)
4931 unitTarget->CastSpell(unitTarget, 59316, true);
4932 // teleport atop
4933 else
4934 unitTarget->CastSpell(unitTarget, 59314, true);
4936 return;
4937 // random spell learn instead placeholder
4938 case 60893: // Northrend Alchemy Research
4939 case 61177: // Northrend Inscription Research
4940 case 61288: // Minor Inscription Research
4941 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4943 if(!IsExplicitDiscoverySpell(m_spellInfo))
4945 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4946 return;
4949 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4950 return;
4951 Player* player = (Player*)m_caster;
4953 // need replace effect 0 item by loot
4954 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4956 if(!player->HasItemCount(reagent_id,1))
4957 return;
4959 // remove reagent
4960 uint32 count = 1;
4961 player->DestroyItemCount (reagent_id,count,true);
4963 // create some random items
4964 player->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
4966 // learn random explicit discovery recipe (if any)
4967 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4968 player->learnSpell(discoveredSpell,false);
4969 return;
4972 break;
4974 case SPELLFAMILY_WARLOCK:
4976 switch(m_spellInfo->Id)
4978 // Healthstone creating spells
4979 case 6201:
4980 case 6202:
4981 case 5699:
4982 case 11729:
4983 case 11730:
4984 case 27230:
4985 case 47871:
4986 case 47878:
4988 uint32 itemtype;
4989 uint32 rank = 0;
4990 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4991 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4993 if((*i)->GetId() == 18692)
4995 rank = 1;
4996 break;
4998 else if((*i)->GetId() == 18693)
5000 rank = 2;
5001 break;
5005 static uint32 const itypes[8][3] = {
5006 { 5512,19004,19005}, // Minor Healthstone
5007 { 5511,19006,19007}, // Lesser Healthstone
5008 { 5509,19008,19009}, // Healthstone
5009 { 5510,19010,19011}, // Greater Healthstone
5010 { 9421,19012,19013}, // Major Healthstone
5011 {22103,22104,22105}, // Master Healthstone
5012 {36889,36890,36891}, // Demonic Healthstone
5013 {36892,36893,36894} // Fel Healthstone
5016 switch(m_spellInfo->Id)
5018 case 6201:
5019 itemtype=itypes[0][rank];break; // Minor Healthstone
5020 case 6202:
5021 itemtype=itypes[1][rank];break; // Lesser Healthstone
5022 case 5699:
5023 itemtype=itypes[2][rank];break; // Healthstone
5024 case 11729:
5025 itemtype=itypes[3][rank];break; // Greater Healthstone
5026 case 11730:
5027 itemtype=itypes[4][rank];break; // Major Healthstone
5028 case 27230:
5029 itemtype=itypes[5][rank];break; // Master Healthstone
5030 case 47871:
5031 itemtype=itypes[6][rank];break; // Demonic Healthstone
5032 case 47878:
5033 itemtype=itypes[7][rank];break; // Fel Healthstone
5034 default:
5035 return;
5037 DoCreateItem( effIndex, itemtype );
5038 return;
5040 // Everlasting Affliction
5041 case 47422:
5043 // Need refresh caster corruption auras on target
5044 Unit::AuraMap& suAuras = unitTarget->GetAuras();
5045 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
5047 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5048 if(spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK &&
5049 spellInfo->SpellFamilyFlags & 0x0000000000000002LL &&
5050 (*itr).second->GetCasterGUID()==m_caster->GetGUID())
5051 (*itr).second->RefreshAura();
5053 return;
5056 break;
5058 case SPELLFAMILY_PRIEST:
5060 switch(m_spellInfo->Id)
5062 // Pain and Suffering
5063 case 47948:
5065 if (!unitTarget)
5066 return;
5067 // Refresh Shadow Word: Pain on target
5068 Unit::AuraMap& auras = unitTarget->GetAuras();
5069 for(Unit::AuraMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
5071 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5072 if( spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST &&
5073 spellInfo->SpellFamilyFlags & 0x0000000000008000LL &&
5074 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
5076 (*itr).second->RefreshAura();
5077 return;
5080 return;
5082 default:
5083 break;
5085 break;
5087 case SPELLFAMILY_HUNTER:
5089 switch(m_spellInfo->Id)
5091 // Chimera Shot
5092 case 53209:
5094 uint32 spellId = 0;
5095 int32 basePoint = 0;
5096 Unit::AuraMap& Auras = unitTarget->GetAuras();
5097 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
5099 Aura *aura = (*i).second;
5100 if (aura->GetCasterGUID() != m_caster->GetGUID())
5101 continue;
5102 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
5103 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
5104 if (!(familyFlag & 0x000000800000C000LL))
5105 continue;
5106 // Refresh aura duration
5107 aura->RefreshAura();
5109 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
5110 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
5112 spellId = 53353; // 53353 Chimera Shot - Serpent
5113 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
5115 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
5116 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
5118 spellId = 53358; // 53358 Chimera Shot - Viper
5119 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
5121 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
5122 if (familyFlag & 0x0000000000008000LL)
5123 spellId = 53359; // 53359 Chimera Shot - Scorpid
5124 // ?? nothing say in spell desc (possibly need addition check)
5125 //if (familyFlag & 0x0000010000000000LL || // dot
5126 // familyFlag & 0x0000100000000000LL) // stun
5128 // spellId = 53366; // 53366 Chimera Shot - Wyvern
5131 if (spellId)
5132 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
5133 return;
5135 default:
5136 break;
5138 break;
5140 case SPELLFAMILY_PALADIN:
5142 // Judgement
5143 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5145 if(!unitTarget || !unitTarget->isAlive())
5146 return;
5147 uint32 spellId1 = 0;
5148 uint32 spellId2 = 0;
5150 // Judgement self add switch
5151 switch (m_spellInfo->Id)
5153 case 41467: break; // Judgement
5154 case 53407: spellId1 = 20184; break; // Judgement of Justice
5155 case 20271: // Judgement of Light
5156 case 57774: spellId1 = 20185; break; // Judgement of Light
5157 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5158 default:
5159 return;
5161 // all seals have aura dummy in 2 effect
5162 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5163 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5165 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5166 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5167 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5168 continue;
5169 spellId2 = (*itr)->GetModifier()->m_amount;
5170 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5171 if (!judge)
5172 continue;
5173 break;
5175 if (spellId1)
5176 m_caster->CastSpell(unitTarget, spellId1, true);
5177 if (spellId2)
5178 m_caster->CastSpell(unitTarget, spellId2, true);
5179 return;
5182 case SPELLFAMILY_POTION:
5184 switch(m_spellInfo->Id)
5186 // Dreaming Glory
5187 case 28698:
5189 if(!unitTarget)
5190 return;
5191 unitTarget->CastSpell(unitTarget, 28694, true);
5192 break;
5194 // Netherbloom
5195 case 28702:
5197 if(!unitTarget)
5198 return;
5199 // 25% chance of casting a random buff
5200 if(roll_chance_i(75))
5201 return;
5203 // triggered spells are 28703 to 28707
5204 // Note: some sources say, that there was the possibility of
5205 // receiving a debuff. However, this seems to be removed by a patch.
5206 const uint32 spellid = 28703;
5208 // don't overwrite an existing aura
5209 for(uint8 i=0; i<5; i++)
5210 if(unitTarget->HasAura(spellid+i, 0))
5211 return;
5212 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5213 break;
5216 // Nightmare Vine
5217 case 28720:
5219 if(!unitTarget)
5220 return;
5221 // 25% chance of casting Nightmare Pollen
5222 if(roll_chance_i(75))
5223 return;
5224 unitTarget->CastSpell(unitTarget, 28721, true);
5225 break;
5228 break;
5232 // normal DB scripted effect
5233 if(!unitTarget)
5234 return;
5236 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5237 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5240 void Spell::EffectSanctuary(uint32 /*i*/)
5242 if(!unitTarget)
5243 return;
5244 //unitTarget->CombatStop();
5246 unitTarget->CombatStop();
5247 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5248 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5249 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5251 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5255 void Spell::EffectAddComboPoints(uint32 /*i*/)
5257 if(!unitTarget)
5258 return;
5260 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5261 return;
5263 if(damage <= 0)
5264 return;
5266 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5269 void Spell::EffectDuel(uint32 i)
5271 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5272 return;
5274 Player *caster = (Player*)m_caster;
5275 Player *target = (Player*)unitTarget;
5277 // caster or target already have requested duel
5278 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5279 return;
5281 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5282 // Don't have to check the target's map since you cannot challenge someone across maps
5283 uint32 mapid = caster->GetMapId();
5284 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5286 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5287 return;
5290 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5291 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5293 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5294 return;
5297 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5298 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5300 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5301 return;
5304 //CREATE DUEL FLAG OBJECT
5305 GameObject* pGameObj = new GameObject;
5307 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5309 Map *map = m_caster->GetMap();
5310 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
5311 map, m_caster->GetPhaseMask(),
5312 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5313 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5314 m_caster->GetPositionZ(),
5315 m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
5317 delete pGameObj;
5318 return;
5321 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5322 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5323 int32 duration = GetSpellDuration(m_spellInfo);
5324 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5325 pGameObj->SetSpellId(m_spellInfo->Id);
5327 m_caster->AddGameObject(pGameObj);
5328 map->Add(pGameObj);
5329 //END
5331 // Send request
5332 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5333 data << pGameObj->GetGUID();
5334 data << caster->GetGUID();
5335 caster->GetSession()->SendPacket(&data);
5336 target->GetSession()->SendPacket(&data);
5338 // create duel-info
5339 DuelInfo *duel = new DuelInfo;
5340 duel->initiator = caster;
5341 duel->opponent = target;
5342 duel->startTime = 0;
5343 duel->startTimer = 0;
5344 caster->duel = duel;
5346 DuelInfo *duel2 = new DuelInfo;
5347 duel2->initiator = caster;
5348 duel2->opponent = caster;
5349 duel2->startTime = 0;
5350 duel2->startTimer = 0;
5351 target->duel = duel2;
5353 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5354 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5357 void Spell::EffectStuck(uint32 /*i*/)
5359 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5360 return;
5362 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5363 return;
5365 Player* pTarget = (Player*)unitTarget;
5367 sLog.outDebug("Spell Effect: Stuck");
5368 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());
5370 if(pTarget->isInFlight())
5371 return;
5373 // homebind location is loaded always
5374 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5376 // Stuck spell trigger Hearthstone cooldown
5377 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5378 if(!spellInfo)
5379 return;
5380 Spell spell(pTarget,spellInfo,true,0);
5381 spell.SendSpellCooldown();
5384 void Spell::EffectSummonPlayer(uint32 /*i*/)
5386 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5387 return;
5389 // Evil Twin (ignore player summon, but hide this for summoner)
5390 if(unitTarget->GetDummyAura(23445))
5391 return;
5393 float x,y,z;
5394 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5396 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5398 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5399 data << uint64(m_caster->GetGUID()); // summoner guid
5400 data << uint32(m_caster->GetZoneId()); // summoner zone
5401 data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILISECONDS); // auto decline after msecs
5402 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5405 static ScriptInfo generateActivateCommand()
5407 ScriptInfo si;
5408 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5409 return si;
5412 void Spell::EffectActivateObject(uint32 effect_idx)
5414 if(!gameObjTarget)
5415 return;
5417 static ScriptInfo activateCommand = generateActivateCommand();
5419 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5421 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5424 void Spell::EffectApplyGlyph(uint32 i)
5426 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5427 return;
5429 Player *player = (Player*)m_caster;
5431 // apply new one
5432 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5434 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5436 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5438 if(gp->TypeFlags != gs->TypeFlags)
5440 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5441 return; // glyph slot mismatch
5445 // remove old glyph
5446 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5448 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5450 player->RemoveAurasDueToSpell(old_gp->SpellId);
5451 player->SetGlyph(m_glyphIndex, 0);
5455 player->CastSpell(m_caster, gp->SpellId, true);
5456 player->SetGlyph(m_glyphIndex, glyph);
5461 void Spell::EffectSummonTotem(uint32 i)
5463 uint8 slot = 0;
5464 switch(m_spellInfo->EffectMiscValueB[i])
5466 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5467 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5468 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5469 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5470 // Battle standard case
5471 case SUMMON_TYPE_TOTEM: slot = 254; break;
5472 // jewelery statue case, like totem without slot
5473 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5474 default: return;
5477 if(slot < MAX_TOTEM)
5479 uint64 guid = m_caster->m_TotemSlot[slot];
5480 if(guid != 0)
5482 Creature *OldTotem = m_caster->GetMap()->GetCreature(guid);
5483 if(OldTotem && OldTotem->isTotem())
5484 ((Totem*)OldTotem)->UnSummon();
5488 uint32 team = 0;
5489 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5490 team = ((Player*)m_caster)->GetTeam();
5492 Totem* pTotem = new Totem;
5494 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
5495 m_spellInfo->EffectMiscValue[i], team ))
5497 delete pTotem;
5498 return;
5501 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5503 float x,y,z;
5504 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5506 // totem must be at same Z in case swimming caster and etc.
5507 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5508 z = m_caster->GetPositionZ();
5510 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5512 if(slot < MAX_TOTEM)
5513 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5515 pTotem->SetOwner(m_caster->GetGUID());
5516 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5518 int32 duration=GetSpellDuration(m_spellInfo);
5519 if(Player* modOwner = m_caster->GetSpellModOwner())
5520 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5521 pTotem->SetDuration(duration);
5523 if (damage) // if not spell info, DB values used
5525 pTotem->SetMaxHealth(damage);
5526 pTotem->SetHealth(damage);
5529 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5531 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5532 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5534 pTotem->Summon(m_caster);
5536 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5538 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5539 data << uint8(slot);
5540 data << uint64(pTotem->GetGUID());
5541 data << uint32(duration);
5542 data << uint32(m_spellInfo->Id);
5543 ((Player*)m_caster)->SendDirectMessage(&data);
5547 void Spell::EffectEnchantHeldItem(uint32 i)
5549 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5550 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5551 return;
5553 Player* item_owner = (Player*)unitTarget;
5554 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5556 if(!item )
5557 return;
5559 // must be equipped
5560 if(!item ->IsEquipped())
5561 return;
5563 if (m_spellInfo->EffectMiscValue[i])
5565 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5566 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5567 if(!duration)
5568 duration = m_currentBasePoints[i]+1; //Base points after ..
5569 if(!duration)
5570 duration = 10; //10 seconds for enchants which don't have listed duration
5572 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5573 if(!pEnchant)
5574 return;
5576 // Always go to temp enchantment slot
5577 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5579 // Enchantment will not be applied if a different one already exists
5580 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5581 return;
5583 // Apply the temporary enchantment
5584 item->SetEnchantment(slot, enchant_id, duration*IN_MILISECONDS, 0);
5585 item_owner->ApplyEnchantment(item,slot,true);
5589 void Spell::EffectDisEnchant(uint32 /*i*/)
5591 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5592 return;
5594 Player* p_caster = (Player*)m_caster;
5595 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5596 return;
5598 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5600 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5602 // item will be removed at disenchanting end
5605 void Spell::EffectInebriate(uint32 /*i*/)
5607 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5608 return;
5610 Player *player = (Player*)unitTarget;
5611 uint16 currentDrunk = player->GetDrunkValue();
5612 uint16 drunkMod = damage * 256;
5613 if (currentDrunk + drunkMod > 0xFFFF)
5614 currentDrunk = 0xFFFF;
5615 else
5616 currentDrunk += drunkMod;
5617 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5620 void Spell::EffectFeedPet(uint32 i)
5622 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5623 return;
5625 Player *_player = (Player*)m_caster;
5627 Item* foodItem = m_targets.getItemTarget();
5628 if(!foodItem)
5629 return;
5631 Pet *pet = _player->GetPet();
5632 if(!pet)
5633 return;
5635 if(!pet->isAlive())
5636 return;
5638 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5639 if(benefit <= 0)
5640 return;
5642 uint32 count = 1;
5643 _player->DestroyItemCount(foodItem,count,true);
5644 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5646 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5649 void Spell::EffectDismissPet(uint32 /*i*/)
5651 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5652 return;
5654 Pet* pet = m_caster->GetPet();
5656 // not let dismiss dead pet
5657 if(!pet||!pet->isAlive())
5658 return;
5660 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5663 void Spell::EffectSummonObject(uint32 i)
5665 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5667 uint8 slot = 0;
5668 switch(m_spellInfo->Effect[i])
5670 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5671 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5672 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5673 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5674 default: return;
5677 uint64 guid = m_caster->m_ObjectSlot[slot];
5678 if(guid != 0)
5680 GameObject* obj = NULL;
5681 if( m_caster )
5682 obj = m_caster->GetMap()->GetGameObject(guid);
5684 if(obj) obj->Delete();
5685 m_caster->m_ObjectSlot[slot] = 0;
5688 GameObject* pGameObj = new GameObject;
5690 float x,y,z;
5691 // If dest location if present
5692 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5694 x = m_targets.m_destX;
5695 y = m_targets.m_destY;
5696 z = m_targets.m_destZ;
5698 // Summon in random point all other units if location present
5699 else
5700 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5702 Map *map = m_caster->GetMap();
5703 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
5704 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY))
5706 delete pGameObj;
5707 return;
5710 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5711 int32 duration = GetSpellDuration(m_spellInfo);
5712 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5713 pGameObj->SetSpellId(m_spellInfo->Id);
5714 m_caster->AddGameObject(pGameObj);
5716 map->Add(pGameObj);
5717 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5718 data << pGameObj->GetGUID();
5719 m_caster->SendMessageToSet(&data,true);
5721 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5724 void Spell::EffectResurrect(uint32 /*effIndex*/)
5726 if(!unitTarget)
5727 return;
5728 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5729 return;
5731 if(unitTarget->isAlive())
5732 return;
5733 if(!unitTarget->IsInWorld())
5734 return;
5736 switch (m_spellInfo->Id)
5738 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5739 case 8342:
5740 if (roll_chance_i(67))
5742 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5743 return;
5745 break;
5746 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5747 case 22999:
5748 if (roll_chance_i(50))
5750 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5751 return;
5753 break;
5754 default:
5755 break;
5758 Player* pTarget = ((Player*)unitTarget);
5760 if(pTarget->isRessurectRequested()) // already have one active request
5761 return;
5763 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5764 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5766 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5767 SendResurrectRequest(pTarget);
5770 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5772 if(!unitTarget || !unitTarget->isAlive())
5773 return;
5775 if( unitTarget->m_extraAttacks )
5776 return;
5778 unitTarget->m_extraAttacks = damage;
5781 void Spell::EffectParry(uint32 /*i*/)
5783 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5784 ((Player*)unitTarget)->SetCanParry(true);
5787 void Spell::EffectBlock(uint32 /*i*/)
5789 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5790 ((Player*)unitTarget)->SetCanBlock(true);
5793 void Spell::EffectMomentMove(uint32 i)
5795 if(unitTarget->isInFlight())
5796 return;
5798 if( m_spellInfo->rangeIndex== 1) //self range
5800 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5802 // before caster
5803 float fx,fy,fz;
5804 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5805 float ox,oy,oz;
5806 unitTarget->GetPosition(ox,oy,oz);
5808 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5809 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5811 fx = fx2;
5812 fy = fy2;
5813 fz = fz2;
5814 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5817 unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(),unitTarget==m_caster);
5821 void Spell::EffectReputation(uint32 i)
5823 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5824 return;
5826 Player *_player = (Player*)unitTarget;
5828 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5830 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5832 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5834 if(!factionEntry)
5835 return;
5837 _player->GetReputationMgr().ModifyReputation(factionEntry,rep_change);
5840 void Spell::EffectQuestComplete(uint32 i)
5842 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5843 return;
5845 Player *_player = (Player*)m_caster;
5847 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5848 _player->AreaExploredOrEventHappens(quest_id);
5851 void Spell::EffectSelfResurrect(uint32 i)
5853 if(!unitTarget || unitTarget->isAlive())
5854 return;
5855 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5856 return;
5857 if(!unitTarget->IsInWorld())
5858 return;
5860 uint32 health = 0;
5861 uint32 mana = 0;
5863 // flat case
5864 if(damage < 0)
5866 health = uint32(-damage);
5867 mana = m_spellInfo->EffectMiscValue[i];
5869 // percent case
5870 else
5872 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5873 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5874 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5877 Player *plr = ((Player*)unitTarget);
5878 plr->ResurrectPlayer(0.0f);
5880 plr->SetHealth( health );
5881 plr->SetPower(POWER_MANA, mana );
5882 plr->SetPower(POWER_RAGE, 0 );
5883 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5885 plr->SpawnCorpseBones();
5887 plr->SaveToDB();
5890 void Spell::EffectSkinning(uint32 /*i*/)
5892 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5893 return;
5894 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5895 return;
5897 Creature* creature = (Creature*) unitTarget;
5898 int32 targetLevel = creature->getLevel();
5900 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5902 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5903 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5905 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5907 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5909 // Double chances for elites
5910 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5913 void Spell::EffectCharge(uint32 /*i*/)
5915 if(!unitTarget || !m_caster)
5916 return;
5918 float x, y, z;
5919 unitTarget->GetContactPoint(m_caster, x, y, z);
5920 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5921 ((Creature *)unitTarget)->StopMoving();
5923 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5924 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5926 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5927 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5929 // not all charge effects used in negative spells
5930 if ( !IsPositiveSpell(m_spellInfo->Id))
5931 m_caster->Attack(unitTarget,true);
5934 void Spell::EffectSummonCritter(uint32 i)
5936 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5937 return;
5938 Player* player = (Player*)m_caster;
5940 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5941 if(!pet_entry)
5942 return;
5944 Pet* old_critter = player->GetMiniPet();
5946 // for same pet just despawn
5947 if(old_critter && old_critter->GetEntry() == pet_entry)
5949 player->RemoveMiniPet();
5950 return;
5953 // despawn old pet before summon new
5954 if(old_critter)
5955 player->RemoveMiniPet();
5957 // summon new pet
5958 Pet* critter = new Pet(MINI_PET);
5960 Map *map = m_caster->GetMap();
5961 uint32 pet_number = objmgr.GeneratePetNumber();
5962 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
5963 pet_entry, pet_number))
5965 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5966 delete critter;
5967 return;
5970 float x,y,z;
5971 // If dest location if present
5972 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5974 x = m_targets.m_destX;
5975 y = m_targets.m_destY;
5976 z = m_targets.m_destZ;
5978 // Summon if dest location not present near caster
5979 else
5980 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5982 critter->Relocate(x,y,z,m_caster->GetOrientation());
5984 if(!critter->IsPositionValid())
5986 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5987 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5988 delete critter;
5989 return;
5992 critter->SetOwnerGUID(m_caster->GetGUID());
5993 critter->SetCreatorGUID(m_caster->GetGUID());
5994 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5995 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5997 critter->AIM_Initialize();
5998 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5999 critter->SelectLevel(critter->GetCreatureInfo()); // some summoned creaters have different from 1 DB data for level/hp
6000 critter->SetUInt32Value(UNIT_NPC_FLAGS, critter->GetCreatureInfo()->npcflag);
6001 // some mini-pets have quests
6003 // set timer for unsummon
6004 int32 duration = GetSpellDuration(m_spellInfo);
6005 if(duration > 0)
6006 critter->SetDuration(duration);
6008 std::string name = player->GetName();
6009 name.append(petTypeSuffix[critter->getPetType()]);
6010 critter->SetName( name );
6011 player->SetMiniPet(critter);
6013 map->Add((Creature*)critter);
6016 void Spell::EffectKnockBack(uint32 i)
6018 if(!unitTarget || !m_caster)
6019 return;
6021 // Effect only works on players
6022 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6023 return;
6025 float vsin = sin(m_caster->GetAngle(unitTarget));
6026 float vcos = cos(m_caster->GetAngle(unitTarget));
6028 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6029 data.append(unitTarget->GetPackGUID());
6030 data << uint32(0); // Sequence
6031 data << float(vcos); // x direction
6032 data << float(vsin); // y direction
6033 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
6034 data << float(damage/-10); // Z Movement speed (vertical)
6036 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6039 void Spell::EffectSendTaxi(uint32 i)
6041 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6042 return;
6044 ((Player*)unitTarget)->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id);
6047 void Spell::EffectPlayerPull(uint32 i)
6049 if(!unitTarget || !m_caster)
6050 return;
6052 // Effect only works on players
6053 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6054 return;
6056 float vsin = sin(unitTarget->GetAngle(m_caster));
6057 float vcos = cos(unitTarget->GetAngle(m_caster));
6059 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6060 data.append(unitTarget->GetPackGUID());
6061 data << uint32(0); // Sequence
6062 data << float(vcos); // x direction
6063 data << float(vsin); // y direction
6064 // Horizontal speed
6065 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
6066 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
6068 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6071 void Spell::EffectDispelMechanic(uint32 i)
6073 if(!unitTarget)
6074 return;
6076 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
6078 Unit::AuraMap& Auras = unitTarget->GetAuras();
6079 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
6081 next = iter;
6082 ++next;
6083 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
6084 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
6086 unitTarget->RemoveAurasDueToSpell(spell->Id);
6087 if(Auras.empty())
6088 break;
6089 else
6090 next = Auras.begin();
6093 return;
6096 void Spell::EffectSummonDeadPet(uint32 /*i*/)
6098 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6099 return;
6100 Player *_player = (Player*)m_caster;
6101 Pet *pet = _player->GetPet();
6102 if(!pet)
6103 return;
6104 if(pet->isAlive())
6105 return;
6106 if(damage < 0)
6107 return;
6108 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6109 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6110 pet->setDeathState( ALIVE );
6111 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6112 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6114 pet->AIM_Initialize();
6116 _player->PetSpellInitialize();
6117 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6120 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6122 int32 mana = 0;
6123 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6125 if(!m_caster->m_TotemSlot[slot])
6126 continue;
6128 Creature* totem = m_caster->GetMap()->GetCreature(m_caster->m_TotemSlot[slot]);
6129 if(totem && totem->isTotem())
6131 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6132 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6133 if(spellInfo)
6135 uint32 manacost = m_caster->GetCreateMana() * spellInfo->ManaCostPercentage / 100;
6136 mana += manacost * damage / 100;
6138 ((Totem*)totem)->UnSummon();
6142 if (mana)
6143 m_caster->CastCustomSpell(m_caster, 39104, &mana, NULL, NULL, true);
6146 void Spell::EffectDurabilityDamage(uint32 i)
6148 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6149 return;
6151 int32 slot = m_spellInfo->EffectMiscValue[i];
6153 // FIXME: some spells effects have value -1/-2
6154 // Possibly its mean -1 all player equipped items and -2 all items
6155 if(slot < 0)
6157 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6158 return;
6161 // invalid slot value
6162 if(slot >= INVENTORY_SLOT_BAG_END)
6163 return;
6165 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6166 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6169 void Spell::EffectDurabilityDamagePCT(uint32 i)
6171 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6172 return;
6174 int32 slot = m_spellInfo->EffectMiscValue[i];
6176 // FIXME: some spells effects have value -1/-2
6177 // Possibly its mean -1 all player equipped items and -2 all items
6178 if(slot < 0)
6180 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6181 return;
6184 // invalid slot value
6185 if(slot >= INVENTORY_SLOT_BAG_END)
6186 return;
6188 if(damage <= 0)
6189 return;
6191 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6192 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6195 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6197 if(!unitTarget)
6198 return;
6200 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6203 void Spell::EffectTransmitted(uint32 effIndex)
6205 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6207 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6209 if (!goinfo)
6211 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6212 return;
6215 float fx,fy,fz;
6217 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6219 fx = m_targets.m_destX;
6220 fy = m_targets.m_destY;
6221 fz = m_targets.m_destZ;
6223 //FIXME: this can be better check for most objects but still hack
6224 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6226 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6227 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6229 else
6231 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6232 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6233 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6235 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6238 Map *cMap = m_caster->GetMap();
6240 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6242 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6243 { // but this is not proper, we really need to ignore not materialized objects
6244 SendCastResult(SPELL_FAILED_NOT_HERE);
6245 SendChannelUpdate(0);
6246 return;
6249 // replace by water level in this case
6250 fz = cMap->GetWaterLevel(fx,fy);
6252 // if gameobject is summoning object, it should be spawned right on caster's position
6253 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6255 m_caster->GetPosition(fx,fy,fz);
6258 GameObject* pGameObj = new GameObject;
6260 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6261 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
6263 delete pGameObj;
6264 return;
6267 int32 duration = GetSpellDuration(m_spellInfo);
6269 switch(goinfo->type)
6271 case GAMEOBJECT_TYPE_FISHINGNODE:
6273 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6274 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6276 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6277 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6278 int32 lastSec = 0;
6279 switch(urand(0, 3))
6281 case 0: lastSec = 3; break;
6282 case 1: lastSec = 7; break;
6283 case 2: lastSec = 13; break;
6284 case 3: lastSec = 17; break;
6287 duration = duration - lastSec*IN_MILISECONDS + FISHING_BOBBER_READY_TIME*IN_MILISECONDS;
6288 break;
6290 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6292 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6294 pGameObj->AddUniqueUse((Player*)m_caster);
6295 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6297 break;
6299 case GAMEOBJECT_TYPE_FISHINGHOLE:
6300 case GAMEOBJECT_TYPE_CHEST:
6301 default:
6303 break;
6307 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6309 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6311 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6312 pGameObj->SetSpellId(m_spellInfo->Id);
6314 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
6315 //m_caster->AddGameObject(pGameObj);
6316 //m_ObjToDel.push_back(pGameObj);
6318 cMap->Add(pGameObj);
6320 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6321 data << uint64(pGameObj->GetGUID());
6322 m_caster->SendMessageToSet(&data,true);
6324 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6326 GameObject* linkedGO = new GameObject;
6327 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6328 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY))
6330 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6331 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6332 linkedGO->SetSpellId(m_spellInfo->Id);
6333 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6335 linkedGO->GetMap()->Add(linkedGO);
6337 else
6339 delete linkedGO;
6340 linkedGO = NULL;
6341 return;
6346 void Spell::EffectProspecting(uint32 /*i*/)
6348 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6349 return;
6351 Player* p_caster = (Player*)m_caster;
6352 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6353 return;
6355 if(itemTarget->GetCount() < 5)
6356 return;
6358 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6360 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6361 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6362 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6365 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6368 void Spell::EffectMilling(uint32 /*i*/)
6370 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6371 return;
6373 Player* p_caster = (Player*)m_caster;
6374 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6375 return;
6377 if(itemTarget->GetCount() < 5)
6378 return;
6380 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6382 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6383 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6384 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6387 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6390 void Spell::EffectSkill(uint32 /*i*/)
6392 sLog.outDebug("WORLD: SkillEFFECT");
6395 void Spell::EffectSummonDemon(uint32 i)
6397 // select center of summon position
6398 float center_x = m_targets.m_destX;
6399 float center_y = m_targets.m_destY;
6400 float center_z = m_targets.m_destZ;
6402 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
6404 int32 amount = damage > 0 ? damage : 1;
6406 for(int32 count = 0; count < amount; ++count)
6408 float px, py, pz;
6409 // If dest location if present
6410 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6412 // Summon 1 unit in dest location
6413 if (count == 0)
6415 px = m_targets.m_destX;
6416 py = m_targets.m_destY;
6417 pz = m_targets.m_destZ;
6419 // Summon in random point all other units if location present
6420 else
6421 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
6423 // Summon if dest location not present near caster
6424 else
6425 m_caster->GetClosePoint(px,py,pz,3.0f);
6427 int32 duration = GetSpellDuration(m_spellInfo);
6429 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,duration);
6430 if (!Charmed) // something fatal, not attempt more
6431 return;
6433 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6434 Charmed->SetLevel(m_caster->getLevel());
6436 // TODO: Add damage/mana/hp according to level
6438 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6440 // Enslave demon effect, without mana cost and cooldown
6441 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6443 // Inferno effect
6444 Charmed->CastSpell(Charmed, 22703, true, 0);
6449 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6450 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6451 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6452 This is why we use a half sec delay between the visual effect and the resurrection itself */
6453 void Spell::EffectSpiritHeal(uint32 /*i*/)
6456 if(!unitTarget || unitTarget->isAlive())
6457 return;
6458 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6459 return;
6460 if(!unitTarget->IsInWorld())
6461 return;
6463 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6464 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6465 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6466 ((Player*)unitTarget)->SpawnCorpseBones();
6470 // remove insignia spell effect
6471 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6473 sLog.outDebug("Effect: SkinPlayerCorpse");
6474 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6475 return;
6477 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6480 void Spell::EffectStealBeneficialBuff(uint32 i)
6482 sLog.outDebug("Effect: StealBeneficialBuff");
6484 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6485 return;
6487 std::vector <Aura *> steal_list;
6488 // Create dispel mask by dispel type
6489 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6490 Unit::AuraMap const& auras = unitTarget->GetAuras();
6491 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6493 Aura *aur = (*itr).second;
6494 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6496 // Need check for passive? this
6497 if (aur->IsPositive() && !aur->IsPassive() && !(aur->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE))
6498 steal_list.push_back(aur);
6501 // Ok if exist some buffs for dispel try dispel it
6502 if (!steal_list.empty())
6504 std::list < std::pair<uint32,uint64> > success_list;
6505 int32 list_size = steal_list.size();
6506 // Dispell N = damage buffs (or while exist buffs for dispel)
6507 for (int32 count=0; count < damage && list_size > 0; ++count)
6509 // Random select buff for dispel
6510 Aura *aur = steal_list[urand(0, list_size-1)];
6511 // Not use chance for steal
6512 // TODO possible need do it
6513 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6515 // Remove buff from list for prevent doubles
6516 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6518 Aura *stealed = *j;
6519 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6521 j = steal_list.erase(j);
6522 --list_size;
6524 else
6525 ++j;
6528 // Really try steal and send log
6529 if (!success_list.empty())
6531 int32 count = success_list.size();
6532 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6533 data.append(unitTarget->GetPackGUID()); // Victim GUID
6534 data.append(m_caster->GetPackGUID()); // Caster GUID
6535 data << uint32(m_spellInfo->Id); // Dispell spell id
6536 data << uint8(0); // not used
6537 data << uint32(count); // count
6538 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6540 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6541 data << uint32(spellInfo->Id); // Spell Id
6542 data << uint8(0); // 0 - steals !=0 transfers
6543 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6545 m_caster->SendMessageToSet(&data, true);
6550 void Spell::EffectKillCredit(uint32 i)
6552 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6553 return;
6555 ((Player*)unitTarget)->RewardPlayerAndGroupAtEvent(m_spellInfo->EffectMiscValue[i], unitTarget);
6558 void Spell::EffectQuestFail(uint32 i)
6560 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6561 return;
6563 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6566 void Spell::EffectActivateRune(uint32 eff_idx)
6568 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6569 return;
6571 Player *plr = (Player*)m_caster;
6573 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6574 return;
6576 for(uint32 j = 0; j < MAX_RUNES; ++j)
6578 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6580 plr->SetRuneCooldown(j, 0);
6585 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6587 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6588 ((Player*)unitTarget)->SetCanTitanGrip(true);
6591 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6593 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6594 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6595 return;
6597 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);