Prevent crash at access to deleted social data for player.
[getmangos.git] / src / game / SpellEffects.cpp
blobe71114367ee4bf4ebdeee8520212f36f4ebf87f9
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
52 #include "Language.h"
53 #include "SocialMgr.h"
54 #include "Util.h"
55 #include "TemporarySummon.h"
57 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
59 &Spell::EffectNULL, // 0
60 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
61 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
62 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
63 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
64 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
65 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
66 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
67 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
68 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
69 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
70 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
71 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
72 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
73 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
74 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
75 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
76 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
77 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
78 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
79 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
80 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
81 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
82 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
83 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
84 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
85 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
86 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
87 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
88 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
89 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
90 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
91 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
92 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
93 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
94 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
95 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
96 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
97 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
98 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
99 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
100 &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
101 &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
102 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
103 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
104 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
105 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
106 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
107 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
108 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
109 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
110 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
111 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
112 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
113 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
114 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
115 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
116 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
117 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
118 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
119 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
120 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
121 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
122 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
123 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
124 &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
125 &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
126 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
127 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
128 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
129 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
130 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
131 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
132 &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
133 &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
134 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
135 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
136 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
137 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
138 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
139 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
140 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
141 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
142 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
143 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
144 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
145 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
146 &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
147 &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
148 &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
149 &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
150 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
151 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
152 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
153 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
154 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
155 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
156 &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
157 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
158 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
159 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
160 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
161 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
162 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
163 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
164 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
165 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
166 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
167 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
168 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
169 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
170 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
171 &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
172 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
173 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
174 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
175 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
176 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
177 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
178 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
179 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
180 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
181 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
182 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
183 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
184 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
185 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
186 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
187 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
188 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
189 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
190 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
191 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
192 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
193 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
194 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
195 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
196 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
197 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
198 &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
199 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
200 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
201 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
202 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
203 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
204 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
205 &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
206 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
207 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
208 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
209 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
210 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
211 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
212 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
215 void Spell::EffectNULL(uint32 /*i*/)
217 sLog.outDebug("WORLD: Spell Effect DUMMY");
220 void Spell::EffectUnused(uint32 /*i*/)
222 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
225 void Spell::EffectResurrectNew(uint32 i)
227 if(!unitTarget || unitTarget->isAlive())
228 return;
230 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
231 return;
233 if(!unitTarget->IsInWorld())
234 return;
236 Player* pTarget = ((Player*)unitTarget);
238 if(pTarget->isRessurectRequested()) // already have one active request
239 return;
241 uint32 health = damage;
242 uint32 mana = m_spellInfo->EffectMiscValue[i];
243 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
244 SendResurrectRequest(pTarget);
247 void Spell::EffectInstaKill(uint32 /*i*/)
249 if( !unitTarget || !unitTarget->isAlive() )
250 return;
252 // Demonic Sacrifice
253 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
255 uint32 entry = unitTarget->GetEntry();
256 uint32 spellID;
257 switch(entry)
259 case 416: spellID=18789; break; //imp
260 case 417: spellID=18792; break; //fellhunter
261 case 1860: spellID=18790; break; //void
262 case 1863: spellID=18791; break; //succubus
263 case 17252: spellID=35701; break; //fellguard
264 default:
265 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
266 return;
269 m_caster->CastSpell(m_caster,spellID,true);
272 if(m_caster==unitTarget) // prevent interrupt message
273 finish();
275 uint32 health = unitTarget->GetHealth();
276 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
279 void Spell::EffectEnvirinmentalDMG(uint32 i)
281 uint32 absorb = 0;
282 uint32 resist = 0;
284 // Note: this hack with damage replace required until GO casting not implemented
285 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
286 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
287 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
289 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
291 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
292 if(m_caster->GetTypeId() == TYPEID_PLAYER)
293 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
296 void Spell::EffectSchoolDMG(uint32 effect_idx)
298 if( unitTarget && unitTarget->isAlive())
300 switch(m_spellInfo->SpellFamilyName)
302 case SPELLFAMILY_GENERIC:
304 //Gore
305 if(m_spellInfo->SpellIconID == 2269 )
307 damage+= rand()%2 ? damage : 0;
310 switch(m_spellInfo->Id) // better way to check unknown
312 // Meteor like spells (divided damage to targets)
313 case 24340: case 26558: case 28884: // Meteor
314 case 36837: case 38903: case 41276: // Meteor
315 case 26789: // Shard of the Fallen Star
316 case 31436: // Malevolent Cleave
317 case 35181: // Dive Bomb
318 case 40810: case 43267: case 43268: // Saber Lash
319 case 42384: // Brutal Swipe
320 case 45150: // Meteor Slash
322 uint32 count = 0;
323 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
324 if(ihit->effectMask & (1<<effect_idx))
325 ++count;
327 damage /= count; // divide to all targets
328 break;
330 // percent from health with min
331 case 25599: // Thundercrash
333 damage = unitTarget->GetHealth() / 2;
334 if(damage < 200)
335 damage = 200;
336 break;
339 break;
342 case SPELLFAMILY_MAGE:
344 // Arcane Blast
345 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
347 m_caster->CastSpell(m_caster,36032,true);
349 break;
351 case SPELLFAMILY_WARRIOR:
353 // Bloodthirst
354 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
356 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
358 // Shield Slam
359 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
360 damage += int32(m_caster->GetShieldBlockValue());
361 // Victory Rush
362 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
364 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
365 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
367 break;
369 case SPELLFAMILY_WARLOCK:
371 // Incinerate Rank 1 & 2
372 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
374 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
375 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
376 damage += int32(damage*0.25);
378 break;
380 case SPELLFAMILY_DRUID:
382 // Ferocious Bite
383 if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
385 // converts each extra point of energy into ($f1+$AP/630) additional damage
386 float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
387 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
388 m_caster->SetPower(POWER_ENERGY,0);
390 // Rake
391 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
393 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
395 // Swipe
396 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
398 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
400 // Starfire
401 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
403 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
404 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
406 // Starfire Bonus (caster)
407 switch((*i)->GetModifier()->m_miscvalue)
409 case 5481: // Nordrassil Regalia - bonus
411 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
412 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
414 // Moonfire or Insect Swarm (target debuff from any casters)
415 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
417 int32 mod = (*i)->GetModifier()->m_amount;
418 damage += damage*mod/100;
419 break;
422 break;
424 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
426 damage += (*i)->GetModifier()->m_amount;
427 break;
432 //Mangle Bonus for the initial damage of Lacerate and Rake
433 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
434 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
436 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
437 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
438 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
440 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
441 break;
444 break;
446 case SPELLFAMILY_ROGUE:
448 // Envenom
449 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
451 // consume from stack dozes not more that have combo-points
452 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
454 // count consumed deadly poison doses at target
455 uint32 doses = 0;
457 // remove consumed poison doses
458 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
459 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
461 // Deadly poison (only attacker applied)
462 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
463 (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
465 --combo;
466 ++doses;
468 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
470 itr = auras.begin();
472 else
473 ++itr;
476 damage *= doses;
477 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
479 // Eviscerate and Envenom Bonus Damage (item set effect)
480 if(m_caster->GetDummyAura(37169))
481 damage += ((Player*)m_caster)->GetComboPoints()*40;
484 // Eviscerate
485 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
487 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
489 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
491 // Eviscerate and Envenom Bonus Damage (item set effect)
492 if(m_caster->GetDummyAura(37169))
493 damage += combo*40;
496 break;
498 case SPELLFAMILY_HUNTER:
500 // Mongoose Bite
501 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
503 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
505 // Arcane Shot
506 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
508 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
510 // Steady Shot
511 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
513 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
514 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
516 //Explosive Trap Effect
517 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
519 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
521 break;
523 case SPELLFAMILY_PALADIN:
525 //Judgement of Vengeance
526 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
528 uint32 stacks = 0;
529 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
530 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
531 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
532 ++stacks;
533 if(!stacks)
534 //No damage if the target isn't affected by this
535 damage = -1;
536 else
537 damage *= stacks;
539 break;
543 if(damage >= 0)
545 uint32 finalDamage;
546 if(m_originalCaster) // m_caster only passive source of cast
547 finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
548 else
549 finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
551 // post effects
552 switch(m_spellInfo->SpellFamilyName)
554 case SPELLFAMILY_WARRIOR:
556 // Bloodthirst
557 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
559 uint32 BTAura = 0;
560 switch(m_spellInfo->Id)
562 case 23881: BTAura = 23885; break;
563 case 23892: BTAura = 23886; break;
564 case 23893: BTAura = 23887; break;
565 case 23894: BTAura = 23888; break;
566 case 25251: BTAura = 25252; break;
567 case 30335: BTAura = 30339; break;
568 default:
569 sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
570 break;
573 if (BTAura)
574 m_caster->CastSpell(m_caster,BTAura,true);
576 break;
578 case SPELLFAMILY_PRIEST:
580 // Shadow Word: Death
581 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
582 // deals damage equal to damage done to caster if victim is not killed
583 m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
585 break;
587 case SPELLFAMILY_PALADIN:
589 // Judgement of Blood
590 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
592 int32 damagePoint = finalDamage * 33 / 100;
593 m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
595 break;
602 void Spell::EffectDummy(uint32 i)
604 if(!unitTarget && !gameObjTarget && !itemTarget)
605 return;
607 // selection by spell family
608 switch(m_spellInfo->SpellFamilyName)
610 case SPELLFAMILY_GENERIC:
611 // Gnomish Poultryizer trinket
612 switch(m_spellInfo->Id )
614 case 8063: // Deviate Fish
616 if(m_caster->GetTypeId() != TYPEID_PLAYER)
617 return;
619 uint32 spell_id = 0;
620 switch(urand(1,5))
622 case 1: spell_id = 8064; break; // Sleepy
623 case 2: spell_id = 8065; break; // Invigorate
624 case 3: spell_id = 8066; break; // Shrink
625 case 4: spell_id = 8067; break; // Party Time!
626 case 5: spell_id = 8068; break; // Healthy Spirit
628 m_caster->CastSpell(m_caster,spell_id,true,NULL);
629 return;
631 case 8213: // Savory Deviate Delight
633 if(m_caster->GetTypeId() != TYPEID_PLAYER)
634 return;
636 uint32 spell_id = 0;
637 switch(urand(1,2))
639 // Flip Out - ninja
640 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
641 // Yaaarrrr - pirate
642 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
644 m_caster->CastSpell(m_caster,spell_id,true,NULL);
645 return;
647 case 8593: // Symbol of life (restore creature to life)
648 case 31225: // Shimmering Vessel (restore creature to life)
650 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
651 return;
652 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
653 return;
655 case 12162: // Deep wounds
656 case 12850: // (now good common check for this spells)
657 case 12868:
659 if(!unitTarget)
660 return;
662 float damage;
663 // DW should benefit of attack power, damage percent mods etc.
664 // TODO: check if using offhand damage is correct and if it should be divided by 2
665 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
666 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
667 else
668 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
670 switch (m_spellInfo->Id)
672 case 12850: damage *= 0.2f; break;
673 case 12162: damage *= 0.4f; break;
674 case 12868: damage *= 0.6f; break;
675 default:
676 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
677 return;
680 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
681 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
682 return;
684 case 12975: //Last Stand
686 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
687 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
688 return;
690 case 13120: // net-o-matic
692 if(!unitTarget)
693 return;
695 uint32 spell_id = 0;
697 uint32 roll = urand(0, 99);
699 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
700 spell_id = 16566;
701 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
702 spell_id = 13119;
703 else // normal root
704 spell_id = 13099;
706 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
707 return;
709 case 13567: // Dummy Trigger
711 // can be used for different aura triggreing, so select by aura
712 if(!m_triggeredByAuraSpell || !unitTarget)
713 return;
715 switch(m_triggeredByAuraSpell->Id)
717 case 26467: // Persistent Shield
718 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
719 break;
720 default:
721 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
722 break;
724 return;
726 case 14185: // Preparation Rogue
728 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
729 return;
731 //immediately finishes the cooldown on certain Rogue abilities
732 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
733 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
735 uint32 classspell = itr->first;
736 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
738 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
740 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
742 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
743 data << uint32(classspell);
744 data << uint64(m_caster->GetGUID());
745 ((Player*)m_caster)->GetSession()->SendPacket(&data);
748 return;
750 case 15998: // Capture Worg Pup
751 case 29435: // Capture Female Kaliri Hatchling
753 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
754 return;
756 Creature* creatureTarget = (Creature*)unitTarget;
757 creatureTarget->setDeathState(JUST_DIED);
758 creatureTarget->RemoveCorpse();
759 creatureTarget->SetHealth(0); // just for nice GM-mode view
760 return;
762 case 16589: // Noggenfogger Elixir
764 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
765 return;
767 uint32 spell_id = 0;
768 switch(urand(1,3))
770 case 1: spell_id = 16595; break;
771 case 2: spell_id = 16593; break;
772 default:spell_id = 16591; break;
775 m_caster->CastSpell(m_caster,spell_id,true,NULL);
776 return;
778 case 17251: // Spirit Healer Res
780 if(!unitTarget || !m_originalCaster)
781 return;
783 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
785 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
786 data << unitTarget->GetGUID();
787 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
789 return;
791 case 17271: // Test Fetid Skull
793 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
794 return;
796 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
798 m_caster->CastSpell(m_caster,spell_id,true,NULL);
799 return;
801 case 20577: // Cannibalize
802 if (unitTarget)
803 m_caster->CastSpell(m_caster,20578,false,NULL);
804 return;
805 case 23019: // Crystal Prison Dummy DND
807 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
808 return;
810 Creature* creatureTarget = (Creature*)unitTarget;
811 if(creatureTarget->isPet())
812 return;
814 creatureTarget->setDeathState(JUST_DIED);
815 creatureTarget->RemoveCorpse();
816 creatureTarget->SetHealth(0); // just for nice GM-mode view
818 GameObject* pGameObj = new GameObject;
820 Map *map = creatureTarget->GetMap();
822 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
823 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
824 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
826 delete pGameObj;
827 return;
830 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
831 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
832 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
833 pGameObj->SetSpellId(m_spellInfo->Id);
835 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
836 map->Add(pGameObj);
838 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
839 data << uint64(pGameObj->GetGUID());
840 m_caster->SendMessageToSet(&data,true);
842 return;
844 case 23074: // Arc. Dragonling
845 if (!m_CastItem) return;
846 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
847 return;
848 case 23075: // Mithril Mechanical Dragonling
849 if (!m_CastItem) return;
850 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
851 return;
852 case 23076: // Mechanical Dragonling
853 if (!m_CastItem) return;
854 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
855 return;
856 case 23133: // Gnomish Battle Chicken
857 if (!m_CastItem) return;
858 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
859 return;
860 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
862 int32 r = irand(0, 119);
863 if ( r < 20 ) // 1/6 polymorph
864 m_caster->CastSpell(m_caster,23444,true);
865 else if ( r < 100 ) // 4/6 evil twin
866 m_caster->CastSpell(m_caster,23445,true);
867 else // 1/6 miss the target
868 m_caster->CastSpell(m_caster,36902,true);
869 return;
871 case 23453: // Ultrasafe Transporter: Gadgetzan
872 if ( roll_chance_i(50) ) // success
873 m_caster->CastSpell(m_caster,23441,true);
874 else // failure
875 m_caster->CastSpell(m_caster,23446,true);
876 return;
877 case 23645: // Hourglass Sand
878 m_caster->RemoveAurasDueToSpell(23170);
879 return;
880 case 23725: // Gift of Life (warrior bwl trinket)
881 m_caster->CastSpell(m_caster,23782,true);
882 m_caster->CastSpell(m_caster,23783,true);
883 return;
884 case 25860: // Reindeer Transformation
886 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
887 return;
889 float flyspeed = m_caster->GetSpeedRate(MOVE_FLY);
890 float speed = m_caster->GetSpeedRate(MOVE_RUN);
892 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
894 //5 different spells used depending on mounted speed and if mount can fly or not
895 if (flyspeed >= 4.1f)
896 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
897 else if (flyspeed >= 3.8f)
898 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
899 else if (flyspeed >= 1.6f)
900 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
901 else if (speed >= 2.0f)
902 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
903 else
904 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
906 return;
908 //case 26074: // Holiday Cheer
909 // return; -- implemented at client side
910 case 28006: // Arcane Cloaking
912 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
913 m_caster->CastSpell(unitTarget,29294,true);
914 return;
916 case 28730: // Arcane Torrent (Mana)
918 int32 count = 0;
919 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
920 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
921 if ((*i)->GetId() == 28734)
922 ++count;
923 if (count)
925 m_caster->RemoveAurasDueToSpell(28734);
926 int32 bp = damage * count;
927 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
929 return;
931 case 29200: // Purify Helboar Meat
933 if( m_caster->GetTypeId() != TYPEID_PLAYER )
934 return;
936 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
938 m_caster->CastSpell(m_caster,spell_id,true,NULL);
939 return;
941 case 29858: // Soulshatter
942 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
943 m_caster->CastSpell(unitTarget,32835,true);
944 return;
945 case 30458: // Nigh Invulnerability
946 if (!m_CastItem) return;
947 if(roll_chance_i(86)) // success
948 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
949 else // backfire in 14% casts
950 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
951 return;
952 case 30507: // Poultryizer
953 if (!m_CastItem) return;
954 if(roll_chance_i(80)) // success
955 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
956 else // backfire 20%
957 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
958 return;
959 case 33060: // Make a Wish
961 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
962 return;
964 uint32 spell_id = 0;
966 switch(urand(1,5))
968 case 1: spell_id = 33053; break;
969 case 2: spell_id = 33057; break;
970 case 3: spell_id = 33059; break;
971 case 4: spell_id = 33062; break;
972 case 5: spell_id = 33064; break;
975 m_caster->CastSpell(m_caster,spell_id,true,NULL);
976 return;
978 case 35745:
980 uint32 spell_id;
981 switch(m_caster->GetAreaId())
983 case 3900: spell_id = 35743; break;
984 case 3742: spell_id = 35744; break;
985 default: return;
988 m_caster->CastSpell(m_caster,spell_id,true);
989 return;
991 case 37674: // Chaos Blast
992 if(unitTarget)
993 m_caster->CastSpell(unitTarget,37675,true);
994 return;
995 case 44875: // Complete Raptor Capture
997 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
998 return;
1000 Creature* creatureTarget = (Creature*)unitTarget;
1002 creatureTarget->setDeathState(JUST_DIED);
1003 creatureTarget->RemoveCorpse();
1004 creatureTarget->SetHealth(0); // just for nice GM-mode view
1006 //cast spell Raptor Capture Credit
1007 m_caster->CastSpell(m_caster,42337,true,NULL);
1008 return;
1010 case 37573: //Temporal Phase Modulator
1012 if(!unitTarget)
1013 return;
1015 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1016 if(!tempSummon)
1017 return;
1019 uint32 health = tempSummon->GetHealth();
1020 const uint32 entry_list[6] = {21821, 21820, 21817};
1022 float x = tempSummon->GetPositionX();
1023 float y = tempSummon->GetPositionY();
1024 float z = tempSummon->GetPositionZ();
1025 float o = tempSummon->GetOrientation();
1027 tempSummon->UnSummon();
1029 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1030 if (!pCreature)
1031 return;
1033 pCreature->SetHealth(health);
1035 if(pCreature->AI())
1036 pCreature->AI()->AttackStart(m_caster);
1038 return;
1040 case 34665: //Administer Antidote
1042 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1043 return;
1045 if(!unitTarget)
1046 return;
1048 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1049 if(!tempSummon)
1050 return;
1052 uint32 health = tempSummon->GetHealth();
1054 float x = tempSummon->GetPositionX();
1055 float y = tempSummon->GetPositionY();
1056 float z = tempSummon->GetPositionZ();
1057 float o = tempSummon->GetOrientation();
1058 tempSummon->UnSummon();
1060 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1061 if (!pCreature)
1062 return;
1064 pCreature->SetHealth(health);
1065 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1067 if (pCreature->AI())
1068 pCreature->AI()->AttackStart(m_caster);
1070 return;
1072 case 44997: // Converting Sentry
1074 //Converted Sentry Credit
1075 m_caster->CastSpell(m_caster, 45009, true);
1076 return;
1078 case 45030: // Impale Emissary
1080 // Emissary of Hate Credit
1081 m_caster->CastSpell(m_caster, 45088, true);
1082 return;
1084 case 50243: // Teach Language
1086 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1087 return;
1089 // spell has a 1/3 chance to trigger one of the below
1090 if(roll_chance_i(66))
1091 return;
1092 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1094 // 1000001 - gnomish binary
1095 m_caster->CastSpell(m_caster, 50242, true);
1097 else
1099 // 01001000 - goblin binary
1100 m_caster->CastSpell(m_caster, 50246, true);
1103 return;
1105 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1107 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1108 return;
1110 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1111 bg->EventPlayerDroppedFlag((Player*)m_caster);
1113 m_caster->CastSpell(m_caster, 30452, true, NULL);
1114 return;
1118 //All IconID Check in there
1119 switch(m_spellInfo->SpellIconID)
1121 // Berserking (troll racial traits)
1122 case 1661:
1124 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1125 int32 melee_mod = 10;
1126 if (healthPerc <= 40)
1127 melee_mod = 30;
1128 if (healthPerc < 100 && healthPerc > 40)
1129 melee_mod = 10+(100-healthPerc)/3;
1131 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1132 int32 hasteModBasePoints1 = (5-melee_mod);
1133 int32 hasteModBasePoints2 = 5;
1135 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1136 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1137 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1138 return;
1141 break;
1142 case SPELLFAMILY_MAGE:
1143 switch(m_spellInfo->Id )
1145 case 11958: // Cold Snap
1147 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1148 return;
1150 // immediately finishes the cooldown on Frost spells
1151 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1152 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1154 if (itr->second->state == PLAYERSPELL_REMOVED)
1155 continue;
1157 uint32 classspell = itr->first;
1158 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1160 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1161 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1162 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1164 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1166 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1167 data << uint32(classspell);
1168 data << uint64(m_caster->GetGUID());
1169 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1172 return;
1174 case 32826:
1176 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1178 //Polymorph Cast Visual Rank 1
1179 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1180 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1182 return;
1185 break;
1186 case SPELLFAMILY_WARRIOR:
1187 // Charge
1188 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
1190 int32 chargeBasePoints0 = damage;
1191 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1192 return;
1194 // Execute
1195 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1197 if(!unitTarget)
1198 return;
1200 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1201 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1202 m_caster->SetPower(POWER_RAGE,0);
1203 return;
1205 if(m_spellInfo->Id==21977) //Warrior's Wrath
1207 if(!unitTarget)
1208 return;
1210 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1211 return;
1213 break;
1214 case SPELLFAMILY_WARLOCK:
1215 //Life Tap (only it have this with dummy effect)
1216 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1218 float cost = m_currentBasePoints[0]+1;
1220 if(Player* modOwner = m_caster->GetSpellModOwner())
1221 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1223 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1225 if(int32(m_caster->GetHealth()) > dmg)
1227 // Shouldn't Appear in Combat Log
1228 m_caster->ModifyHealth(-dmg);
1230 int32 mana = dmg;
1232 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1233 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1235 // only Imp. Life Tap have this in combination with dummy aura
1236 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1237 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1240 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1242 // Mana Feed
1243 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1244 manaFeedVal = manaFeedVal * mana / 100;
1245 if(manaFeedVal > 0)
1246 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1248 else
1249 SendCastResult(SPELL_FAILED_FIZZLE);
1250 return;
1252 break;
1253 case SPELLFAMILY_PRIEST:
1254 switch(m_spellInfo->Id )
1256 case 28598: // Touch of Weakness triggered spell
1258 if(!unitTarget || !m_triggeredByAuraSpell)
1259 return;
1261 uint32 spellid = 0;
1262 switch(m_triggeredByAuraSpell->Id)
1264 case 2652: spellid = 2943; break; // Rank 1
1265 case 19261: spellid = 19249; break; // Rank 2
1266 case 19262: spellid = 19251; break; // Rank 3
1267 case 19264: spellid = 19252; break; // Rank 4
1268 case 19265: spellid = 19253; break; // Rank 5
1269 case 19266: spellid = 19254; break; // Rank 6
1270 case 25461: spellid = 25460; break; // Rank 7
1271 default:
1272 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1273 return;
1275 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1276 return;
1279 break;
1280 case SPELLFAMILY_DRUID:
1281 switch(m_spellInfo->Id )
1283 case 5420: // Tree of Life passive
1285 // Tree of Life area effect
1286 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1287 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1288 return;
1291 break;
1292 case SPELLFAMILY_ROGUE:
1293 switch(m_spellInfo->Id )
1295 case 31231: // Cheat Death
1297 m_caster->CastSpell(m_caster,45182,true);
1298 return;
1300 case 5938: // Shiv
1302 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1303 return;
1305 Player *pCaster = ((Player*)m_caster);
1307 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1308 if(!item)
1309 return;
1311 // all poison enchantments is temporary
1312 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1313 if(!enchant_id)
1314 return;
1316 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1317 if(!pEnchant)
1318 return;
1320 for (int s=0;s<3;s++)
1322 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1323 continue;
1325 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1326 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1327 continue;
1329 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1332 m_caster->CastSpell(unitTarget, 5940, true);
1333 return;
1336 break;
1337 case SPELLFAMILY_HUNTER:
1338 // Steady Shot
1339 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1341 if( !unitTarget || !unitTarget->isAlive())
1342 return;
1344 bool found = false;
1346 // check dazed affect
1347 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1348 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1350 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1352 found = true;
1353 break;
1357 if(found)
1358 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
1359 return;
1361 // Kill command
1362 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1364 if(m_caster->getClass()!=CLASS_HUNTER)
1365 return;
1367 // clear hunter crit aura state
1368 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1370 // additional damage from pet to pet target
1371 Pet* pet = m_caster->GetPet();
1372 if(!pet || !pet->getVictim())
1373 return;
1375 uint32 spell_id = 0;
1376 switch (m_spellInfo->Id)
1378 case 34026: spell_id = 34027; break; // rank 1
1379 default:
1380 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1381 return;
1384 pet->CastSpell(pet->getVictim(), spell_id, true);
1385 return;
1388 switch(m_spellInfo->Id)
1390 case 23989: //Readiness talent
1392 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1393 return;
1395 //immediately finishes the cooldown for hunter abilities
1396 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1397 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1399 uint32 classspell = itr->first;
1400 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1402 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1404 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1406 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1407 data << uint32(classspell);
1408 data << uint64(m_caster->GetGUID());
1409 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1412 return;
1414 case 37506: // Scatter Shot
1416 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1417 return;
1419 // break Auto Shot and autohit
1420 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1421 m_caster->AttackStop();
1422 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1423 return;
1426 break;
1427 case SPELLFAMILY_PALADIN:
1428 switch(m_spellInfo->SpellIconID)
1430 case 156: // Holy Shock
1432 if(!unitTarget)
1433 return;
1435 int hurt = 0;
1436 int heal = 0;
1438 switch(m_spellInfo->Id)
1440 case 20473: hurt = 25912; heal = 25914; break;
1441 case 20929: hurt = 25911; heal = 25913; break;
1442 case 20930: hurt = 25902; heal = 25903; break;
1443 case 27174: hurt = 27176; heal = 27175; break;
1444 case 33072: hurt = 33073; heal = 33074; break;
1445 default:
1446 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1447 return;
1450 if(m_caster->IsFriendlyTo(unitTarget))
1451 m_caster->CastSpell(unitTarget, heal, true, 0);
1452 else
1453 m_caster->CastSpell(unitTarget, hurt, true, 0);
1455 return;
1457 case 561: // Judgement of command
1459 if(!unitTarget)
1460 return;
1462 uint32 spell_id = m_currentBasePoints[i]+1;
1463 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1464 if(!spell_proto)
1465 return;
1467 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1469 // decreased damage (/2) for non-stunned target.
1470 SpellModifier *mod = new SpellModifier;
1471 mod->op = SPELLMOD_DAMAGE;
1472 mod->value = -50;
1473 mod->type = SPELLMOD_PCT;
1474 mod->spellId = m_spellInfo->Id;
1475 mod->effectId = i;
1476 mod->lastAffected = NULL;
1477 mod->mask = 0x0000020000000000LL;
1478 mod->charges = 0;
1480 ((Player*)m_caster)->AddSpellMod(mod, true);
1481 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1482 // mod deleted
1483 ((Player*)m_caster)->AddSpellMod(mod, false);
1485 else
1486 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1488 return;
1492 switch(m_spellInfo->Id)
1494 case 31789: // Righteous Defense (step 1)
1496 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1498 // non-standard cast requirement check
1499 if (!unitTarget || unitTarget->getAttackers().empty())
1501 // clear cooldown at fail
1502 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1504 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1506 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1507 data << uint32(m_spellInfo->Id);
1508 data << uint64(m_caster->GetGUID());
1509 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1512 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1513 return;
1516 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1517 // Clear targets for eff 1
1518 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1519 ihit->effectMask &= ~(1<<1);
1521 // not empty (checked)
1522 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1524 // chance to be selected from list
1525 float chance = 100.0f/attackers.size();
1526 uint32 count=0;
1527 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1529 if(!roll_chance_f(chance))
1530 continue;
1531 ++count;
1532 AddUnitTarget((*aItr), 1);
1535 // now let next effect cast spell at each target.
1536 return;
1538 case 37877: // Blessing of Faith
1540 if(!unitTarget)
1541 return;
1543 uint32 spell_id = 0;
1544 switch(unitTarget->getClass())
1546 case CLASS_DRUID: spell_id = 37878; break;
1547 case CLASS_PALADIN: spell_id = 37879; break;
1548 case CLASS_PRIEST: spell_id = 37880; break;
1549 case CLASS_SHAMAN: spell_id = 37881; break;
1550 default: return; // ignore for not healing classes
1553 m_caster->CastSpell(m_caster,spell_id,true);
1554 return;
1557 break;
1558 case SPELLFAMILY_SHAMAN:
1559 //Shaman Rockbiter Weapon
1560 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1562 uint32 spell_id = 0;
1563 switch(m_spellInfo->Id)
1565 case 8017: spell_id = 36494; break; // Rank 1
1566 case 8018: spell_id = 36750; break; // Rank 2
1567 case 8019: spell_id = 36755; break; // Rank 3
1568 case 10399: spell_id = 36759; break; // Rank 4
1569 case 16314: spell_id = 36763; break; // Rank 5
1570 case 16315: spell_id = 36766; break; // Rank 6
1571 case 16316: spell_id = 36771; break; // Rank 7
1572 case 25479: spell_id = 36775; break; // Rank 8
1573 case 25485: spell_id = 36499; break; // Rank 9
1574 default:
1575 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1576 return;
1579 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1581 if(!spellInfo)
1583 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1584 return;
1587 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1588 return;
1590 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1592 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1594 if(item->IsFitToSpellRequirements(m_spellInfo))
1596 Spell *spell = new Spell(m_caster, spellInfo, true);
1598 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1599 // at calculation applied affect from Elemental Weapons talent
1600 // real enchantment damage-1
1601 spell->m_currentBasePoints[1] = damage-1;
1603 SpellCastTargets targets;
1604 targets.setItemTarget( item );
1605 spell->prepare(&targets);
1609 return;
1612 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1614 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1615 return;
1617 // Regenerate 6% of Total Mana Every 3 secs
1618 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1619 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1620 return;
1623 break;
1626 // pet auras
1627 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1629 m_caster->AddPetAura(petSpell);
1630 return;
1634 void Spell::EffectTriggerSpellWithValue(uint32 i)
1636 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1638 // normal case
1639 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1641 if(!spellInfo)
1643 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1644 return;
1647 int32 bp = damage;
1648 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1651 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1653 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1654 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1656 if(!spellInfo)
1658 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1659 return;
1662 finish();
1663 Spell *spell = new Spell(m_caster, spellInfo, true);
1665 SpellCastTargets targets;
1666 targets.setUnitTarget( unitTarget);
1667 spell->prepare(&targets);
1669 m_caster->SetCurrentCastedSpell(spell);
1670 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1674 void Spell::EffectForceCast(uint32 i)
1676 if( !unitTarget )
1677 return;
1679 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1681 // normal case
1682 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1684 if(!spellInfo)
1686 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1687 return;
1690 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1693 void Spell::EffectTriggerSpell(uint32 i)
1695 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1697 // special cases
1698 switch(triggered_spell_id)
1700 // Vanish
1701 case 18461:
1703 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1704 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1705 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1707 // if this spell is given to NPC it must handle rest by it's own AI
1708 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1709 return;
1711 // get highest rank of the Stealth spell
1712 uint32 spellId = 0;
1713 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1714 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1716 // only highest rank is shown in spell book, so simply check if shown in spell book
1717 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1718 continue;
1720 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1721 if (!spellInfo)
1722 continue;
1724 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1726 spellId = spellInfo->Id;
1727 break;
1731 // no Stealth spell found
1732 if (!spellId)
1733 return;
1735 // reset cooldown on it if needed
1736 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1737 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1739 m_caster->CastSpell(m_caster, spellId, true);
1740 return;
1742 // just skip
1743 case 23770: // Sayge's Dark Fortune of *
1744 // not exist, common cooldown can be implemented in scripts if need.
1745 return;
1746 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1747 case 29284:
1749 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1750 if (!spell)
1751 return;
1753 for (int i=0; i < spell->StackAmount; ++i)
1754 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1755 return;
1757 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1758 case 29286:
1760 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1761 if (!spell)
1762 return;
1764 for (int i=0; i < spell->StackAmount; ++i)
1765 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1766 return;
1768 // Righteous Defense
1769 case 31980:
1771 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1772 return;
1774 // Cloak of Shadows
1775 case 35729 :
1777 Unit::AuraMap& Auras = m_caster->GetAuras();
1778 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1780 // remove all harmful spells on you...
1781 if( // ignore positive and passive auras
1782 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1783 // ignore physical auras
1784 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1785 // ignore immunity persistent spells
1786 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1788 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1789 iter = Auras.begin();
1792 return;
1794 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1795 case 41967:
1797 if (Unit *pet = m_caster->GetPet())
1798 pet->CastSpell(pet, 28305, true);
1799 return;
1803 // normal case
1804 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1806 if(!spellInfo)
1808 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1809 return;
1812 // some triggered spells require specific equipment
1813 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1815 // main hand weapon required
1816 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1818 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1820 // skip spell if no weapon in slot or broken
1821 if(!item || item->IsBroken() )
1822 return;
1824 // skip spell if weapon not fit to triggered spell
1825 if(!item->IsFitToSpellRequirements(spellInfo))
1826 return;
1829 // offhand hand weapon required
1830 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1832 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1834 // skip spell if no weapon in slot or broken
1835 if(!item || item->IsBroken() )
1836 return;
1838 // skip spell if weapon not fit to triggered spell
1839 if(!item->IsFitToSpellRequirements(spellInfo))
1840 return;
1844 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1845 bool instant = false;
1846 for(uint32 j = i+1; j < 3; ++j)
1848 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1850 instant = true;
1851 break;
1855 if(instant)
1857 if (unitTarget)
1858 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1860 else
1861 m_TriggerSpells.push_back(spellInfo);
1864 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1866 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1868 // normal case
1869 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1871 if(!spellInfo)
1873 sLog.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id);
1874 return;
1877 if (m_CastItem)
1878 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1880 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1882 SpellCastTargets targets;
1883 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1884 spell->m_CastItem = m_CastItem;
1885 spell->prepare(&targets, NULL);
1888 void Spell::EffectTeleportUnits(uint32 i)
1890 if(!unitTarget || unitTarget->isInFlight())
1891 return;
1893 switch (m_spellInfo->EffectImplicitTargetB[i])
1895 case TARGET_INNKEEPER_COORDINATES:
1897 // Only players can teleport to innkeeper
1898 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1899 return;
1901 ((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);
1902 return;
1904 case TARGET_TABLE_X_Y_Z_COORDINATES:
1906 // TODO: Only players can teleport?
1907 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1908 return;
1909 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1910 if(!st)
1912 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1913 return;
1915 ((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);
1916 break;
1918 case TARGET_BEHIND_VICTIM:
1920 // Get selected target for player (or victim for units)
1921 Unit *pTarget = NULL;
1922 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1923 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1924 else
1925 pTarget = m_caster->getVictim();
1926 // No target present - return
1927 if (!pTarget)
1928 return;
1929 // Init dest coordinates
1930 uint32 mapid = m_caster->GetMapId();
1931 float x = m_targets.m_destX;
1932 float y = m_targets.m_destY;
1933 float z = m_targets.m_destZ;
1934 float orientation = pTarget->GetOrientation();
1935 // Teleport
1936 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1937 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
1938 else
1940 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1941 WorldPacket data;
1942 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1943 unitTarget->SendMessageToSet(&data, false);
1945 return;
1947 default:
1949 // If not exist data for dest location - return
1950 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
1952 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
1953 return;
1955 // Init dest coordinates
1956 uint32 mapid = m_caster->GetMapId();
1957 float x = m_targets.m_destX;
1958 float y = m_targets.m_destY;
1959 float z = m_targets.m_destZ;
1960 float orientation = unitTarget->GetOrientation();
1961 // Teleport
1962 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1963 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
1964 else
1966 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1967 WorldPacket data;
1968 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1969 unitTarget->SendMessageToSet(&data, false);
1971 return;
1975 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1976 switch ( m_spellInfo->Id )
1978 // Dimensional Ripper - Everlook
1979 case 23442:
1981 int32 r = irand(0, 119);
1982 if ( r >= 70 ) // 7/12 success
1984 if ( r < 100 ) // 4/12 evil twin
1985 m_caster->CastSpell(m_caster,23445,true);
1986 else // 1/12 fire
1987 m_caster->CastSpell(m_caster,23449,true);
1989 return;
1991 // Ultrasafe Transporter: Toshley's Station
1992 case 36941:
1994 if ( roll_chance_i(50) ) // 50% success
1996 int32 rand_eff = urand(1,7);
1997 switch ( rand_eff )
1999 case 1:
2000 // soul split - evil
2001 m_caster->CastSpell(m_caster,36900,true);
2002 break;
2003 case 2:
2004 // soul split - good
2005 m_caster->CastSpell(m_caster,36901,true);
2006 break;
2007 case 3:
2008 // Increase the size
2009 m_caster->CastSpell(m_caster,36895,true);
2010 break;
2011 case 4:
2012 // Decrease the size
2013 m_caster->CastSpell(m_caster,36893,true);
2014 break;
2015 case 5:
2016 // Transform
2018 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2019 m_caster->CastSpell(m_caster,36897,true);
2020 else
2021 m_caster->CastSpell(m_caster,36899,true);
2022 break;
2024 case 6:
2025 // chicken
2026 m_caster->CastSpell(m_caster,36940,true);
2027 break;
2028 case 7:
2029 // evil twin
2030 m_caster->CastSpell(m_caster,23445,true);
2031 break;
2034 return;
2036 // Dimensional Ripper - Area 52
2037 case 36890:
2039 if ( roll_chance_i(50) ) // 50% success
2041 int32 rand_eff = urand(1,4);
2042 switch ( rand_eff )
2044 case 1:
2045 // soul split - evil
2046 m_caster->CastSpell(m_caster,36900,true);
2047 break;
2048 case 2:
2049 // soul split - good
2050 m_caster->CastSpell(m_caster,36901,true);
2051 break;
2052 case 3:
2053 // Increase the size
2054 m_caster->CastSpell(m_caster,36895,true);
2055 break;
2056 case 4:
2057 // Transform
2059 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2060 m_caster->CastSpell(m_caster,36897,true);
2061 else
2062 m_caster->CastSpell(m_caster,36899,true);
2063 break;
2067 return;
2072 void Spell::EffectApplyAura(uint32 i)
2074 if(!unitTarget)
2075 return;
2077 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2078 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2079 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2080 return;
2082 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2083 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2084 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2085 return;
2087 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2088 if(!caster)
2089 return;
2091 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2093 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2095 // Now Reduce spell duration using data received at spell hit
2096 int32 duration = Aur->GetAuraMaxDuration();
2097 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2098 Aur->setDiminishGroup(m_diminishGroup);
2100 // if Aura removed and deleted, do not continue.
2101 if(duration== 0 && !(Aur->IsPermanent()))
2103 delete Aur;
2104 return;
2107 if(duration != Aur->GetAuraMaxDuration())
2109 Aur->SetAuraMaxDuration(duration);
2110 Aur->SetAuraDuration(duration);
2113 bool added = unitTarget->AddAura(Aur);
2115 // Aura not added and deleted in AddAura call;
2116 if (!added)
2117 return;
2119 // found crash at character loading, broken pointer to Aur...
2120 // Aur was deleted in AddAura()...
2121 if(!Aur)
2122 return;
2124 // TODO Make a way so it works for every related spell!
2125 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2127 uint32 spellId = 0;
2128 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2129 spellId = 6788; // Weakened Soul
2130 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2131 spellId = 25771; // Forbearance
2132 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2133 spellId = 41425; // Hypothermia
2134 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2135 spellId = 11196; // Recently Bandaged
2136 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2137 spellId = 23230; // Blood Fury - Healing Reduction
2139 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2140 if (AdditionalSpellInfo)
2142 // applied at target by target
2143 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2144 unitTarget->AddAura(AdditionalAura);
2145 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2149 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2150 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2151 m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
2154 void Spell::EffectUnlearnSpecialization( uint32 i )
2156 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2157 return;
2159 Player *_player = (Player*)unitTarget;
2160 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2162 _player->removeSpell(spellToUnlearn);
2164 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2167 void Spell::EffectPowerDrain(uint32 i)
2169 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2170 return;
2172 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2174 if(!unitTarget)
2175 return;
2176 if(!unitTarget->isAlive())
2177 return;
2178 if(unitTarget->getPowerType() != drain_power)
2179 return;
2180 if(damage < 0)
2181 return;
2183 uint32 curPower = unitTarget->GetPower(drain_power);
2185 //add spell damage bonus
2186 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2188 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2189 uint32 power = damage;
2190 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2191 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2193 int32 new_damage;
2194 if(curPower < power)
2195 new_damage = curPower;
2196 else
2197 new_damage = power;
2199 unitTarget->ModifyPower(drain_power,-new_damage);
2201 if(drain_power == POWER_MANA)
2203 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2204 if(manaMultiplier==0)
2205 manaMultiplier = 1;
2207 if(Player *modOwner = m_caster->GetSpellModOwner())
2208 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2210 int32 gain = int32(new_damage*manaMultiplier);
2212 m_caster->ModifyPower(POWER_MANA,gain);
2213 //send log
2214 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false);
2218 void Spell::EffectSendEvent(uint32 EffectIndex)
2220 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2222 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2223 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2225 switch(m_spellInfo->Id)
2227 case 23333: // Pickup Horde Flag
2228 /*do not uncomment .
2229 if(bg->GetTypeID()==BATTLEGROUND_WS)
2230 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2231 sLog.outDebug("Send Event Horde Flag Picked Up");
2232 break;
2233 /* not used :
2234 case 23334: // Drop Horde Flag
2235 if(bg->GetTypeID()==BATTLEGROUND_WS)
2236 bg->EventPlayerDroppedFlag((Player*)m_caster);
2237 sLog.outDebug("Drop Horde Flag");
2238 break;
2240 case 23335: // Pickup Alliance Flag
2241 /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
2242 if(bg->GetTypeID()==BATTLEGROUND_WS)
2243 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2244 sLog.outDebug("Send Event Alliance Flag Picked Up");
2245 break;
2246 /* not used :
2247 case 23336: // Drop Alliance Flag
2248 if(bg->GetTypeID()==BATTLEGROUND_WS)
2249 bg->EventPlayerDroppedFlag((Player*)m_caster);
2250 sLog.outDebug("Drop Alliance Flag");
2251 break;
2252 case 23385: // Alliance Flag Returns
2253 if(bg->GetTypeID()==BATTLEGROUND_WS)
2254 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2255 sLog.outDebug("Alliance Flag Returned");
2256 break;
2257 case 23386: // Horde Flag Returns
2258 if(bg->GetTypeID()==BATTLEGROUND_WS)
2259 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2260 sLog.outDebug("Horde Flag Returned");
2261 break;*/
2262 case 34976:
2264 if(bg->GetTypeID()==BATTLEGROUND_EY)
2265 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2267 break;
2268 default:
2269 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2270 break;
2274 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2275 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2278 void Spell::EffectPowerBurn(uint32 i)
2280 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2281 return;
2283 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2285 if(!unitTarget)
2286 return;
2287 if(!unitTarget->isAlive())
2288 return;
2289 if(unitTarget->getPowerType()!=powertype)
2290 return;
2291 if(damage < 0)
2292 return;
2294 int32 curPower = int32(unitTarget->GetPower(powertype));
2296 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2297 uint32 power = damage;
2298 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2299 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2301 int32 new_damage = (curPower < power) ? curPower : power;
2303 unitTarget->ModifyPower(powertype,-new_damage);
2304 float multiplier = m_spellInfo->EffectMultipleValue[i];
2306 if(Player *modOwner = m_caster->GetSpellModOwner())
2307 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2309 new_damage = int32(new_damage*multiplier);
2310 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2313 void Spell::EffectHeal( uint32 /*i*/ )
2315 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2317 // Try to get original caster
2318 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2320 // Skip if m_originalCaster not available
2321 if (!caster)
2322 return;
2324 int32 addhealth = damage;
2326 // Vessel of the Naaru (Vial of the Sunwell trinket)
2327 if (m_spellInfo->Id == 45064)
2329 // Amount of heal - depends from stacked Holy Energy
2330 int damageAmount = 0;
2331 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2332 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2333 if((*i)->GetId() == 45062)
2334 damageAmount+=(*i)->GetModifier()->m_amount;
2335 if (damageAmount)
2336 m_caster->RemoveAurasDueToSpell(45062);
2338 addhealth += damageAmount;
2340 // Swiftmend - consumes Regrowth or Rejuvenation
2341 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2343 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2344 // find most short by duration
2345 Aura *targetAura = NULL;
2346 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2348 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2349 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2351 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2352 targetAura = *i;
2356 if(!targetAura)
2358 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2359 return;
2361 int idx = 0;
2362 while(idx < 3)
2364 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2365 break;
2366 idx++;
2369 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2370 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2371 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2373 addhealth += tickheal * tickcount;
2375 else
2376 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2378 bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
2379 if (crit)
2380 addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
2381 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
2383 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2384 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2386 if(caster->GetTypeId()==TYPEID_PLAYER)
2387 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2388 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2390 // ignore item heals
2391 if(m_CastItem)
2392 return;
2394 uint32 procHealer = PROC_FLAG_HEAL;
2395 if (crit)
2396 procHealer |= PROC_FLAG_CRIT_HEAL;
2398 m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
2402 void Spell::EffectHealPct( uint32 /*i*/ )
2404 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2406 // Try to get original caster
2407 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2409 // Skip if m_originalCaster not available
2410 if (!caster)
2411 return;
2413 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2414 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2416 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2417 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2419 if(caster->GetTypeId()==TYPEID_PLAYER)
2420 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2421 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2425 void Spell::EffectHealMechanical( uint32 /*i*/ )
2427 // Mechanic creature type should be correctly checked by targetCreatureType field
2428 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2430 // Try to get original caster
2431 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2433 // Skip if m_originalCaster not available
2434 if (!caster)
2435 return;
2437 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2438 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2439 unitTarget->ModifyHealth( int32(damage) );
2443 void Spell::EffectHealthLeech(uint32 i)
2445 if(!unitTarget)
2446 return;
2447 if(!unitTarget->isAlive())
2448 return;
2450 if(damage < 0)
2451 return;
2453 sLog.outDebug("HealthLeech :%i", damage);
2455 float multiplier = m_spellInfo->EffectMultipleValue[i];
2457 if(Player *modOwner = m_caster->GetSpellModOwner())
2458 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2460 int32 new_damage = int32(damage*multiplier);
2461 uint32 curHealth = unitTarget->GetHealth();
2462 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2463 if(curHealth < new_damage)
2464 new_damage = curHealth;
2466 if(m_caster->isAlive())
2468 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2470 m_caster->ModifyHealth(new_damage);
2472 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2473 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2477 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2479 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2480 return;
2482 Player* player = (Player*)unitTarget;
2484 uint32 newitemid = itemtype;
2485 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2486 if(!pProto)
2488 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2489 return;
2492 uint32 num_to_add;
2494 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2495 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2497 int32 basePoints = m_currentBasePoints[i];
2498 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2499 if (randomPoints)
2500 num_to_add = basePoints + irand(1, randomPoints);
2501 else
2502 num_to_add = basePoints + 1;
2504 else if (pProto->MaxCount == 1)
2505 num_to_add = 1;
2506 else if(player->getLevel() >= m_spellInfo->spellLevel)
2508 int32 basePoints = m_currentBasePoints[i];
2509 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2510 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2512 else
2513 num_to_add = 2;
2515 if (num_to_add < 1)
2516 num_to_add = 1;
2517 if (num_to_add > pProto->Stackable)
2518 num_to_add = pProto->Stackable;
2520 // init items_count to 1, since 1 item will be created regardless of specialization
2521 int items_count=1;
2522 // the chance to create additional items
2523 float additionalCreateChance=0.0f;
2524 // the maximum number of created additional items
2525 uint8 additionalMaxNum=0;
2526 // get the chance and maximum number for creating extra items
2527 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2529 // roll with this chance till we roll not to create or we create the max num
2530 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2531 ++items_count;
2534 // really will be created more items
2535 num_to_add *= items_count;
2537 // can the player store the new item?
2538 ItemPosCountVec dest;
2539 uint32 no_space = 0;
2540 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2541 if( msg != EQUIP_ERR_OK )
2543 // convert to possible store amount
2544 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2545 num_to_add -= no_space;
2546 else
2548 // if not created by another reason from full inventory or unique items amount limitation
2549 player->SendEquipError( msg, NULL, NULL );
2550 return;
2554 if(num_to_add)
2556 // create the new item and store it
2557 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2559 // was it successful? return error if not
2560 if(!pItem)
2562 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2563 return;
2566 // set the "Crafted by ..." property of the item
2567 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2568 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2570 // send info to the client
2571 if(pItem)
2572 player->SendNewItem(pItem, num_to_add, true, true);
2574 // we succeeded in creating at least one item, so a levelup is possible
2575 player->UpdateCraftSkill(m_spellInfo->Id);
2578 // for battleground marks send by mail if not add all expected
2579 if(no_space > 0 )
2581 BattleGroundTypeId bgType;
2582 switch(m_spellInfo->Id)
2584 case SPELL_AV_MARK_WINNER:
2585 case SPELL_AV_MARK_LOSER:
2586 bgType = BATTLEGROUND_AV;
2587 break;
2588 case SPELL_WS_MARK_WINNER:
2589 case SPELL_WS_MARK_LOSER:
2590 bgType = BATTLEGROUND_WS;
2591 break;
2592 case SPELL_AB_MARK_WINNER:
2593 case SPELL_AB_MARK_LOSER:
2594 bgType = BATTLEGROUND_AB;
2595 break;
2596 default:
2597 return;
2600 if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
2601 bg->SendRewardMarkByMail(player,newitemid,no_space);
2605 void Spell::EffectCreateItem(uint32 i)
2607 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2610 void Spell::EffectPersistentAA(uint32 i)
2612 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2614 if(Player* modOwner = m_caster->GetSpellModOwner())
2615 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2617 int32 duration = GetSpellDuration(m_spellInfo);
2618 DynamicObject* dynObj = new DynamicObject;
2619 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))
2621 delete dynObj;
2622 return;
2624 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2625 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2626 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2627 m_caster->AddDynObject(dynObj);
2628 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
2631 void Spell::EffectEnergize(uint32 i)
2633 if(!unitTarget)
2634 return;
2635 if(!unitTarget->isAlive())
2636 return;
2638 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2639 return;
2641 // Some level depends spells
2642 int multipler = 0;
2643 int level_diff = 0;
2644 switch (m_spellInfo->Id)
2646 // Restore Energy
2647 case 9512:
2648 level_diff = m_caster->getLevel() - 40;
2649 multipler = 2;
2650 break;
2651 // Blood Fury
2652 case 24571:
2653 level_diff = m_caster->getLevel() - 60;
2654 multipler = 10;
2655 break;
2656 // Burst of Energy
2657 case 24532:
2658 level_diff = m_caster->getLevel() - 60;
2659 multipler = 4;
2660 break;
2661 default:
2662 break;
2665 if (level_diff > 0)
2666 damage -= multipler * level_diff;
2668 if(damage < 0)
2669 return;
2671 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2673 if(unitTarget->GetMaxPower(power) == 0)
2674 return;
2676 unitTarget->ModifyPower(power,damage);
2677 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2679 // Mad Alchemist's Potion
2680 if (m_spellInfo->Id == 45051)
2682 // find elixirs on target
2683 uint32 elixir_mask = 0;
2684 Unit::AuraMap& Auras = unitTarget->GetAuras();
2685 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2687 uint32 spell_id = itr->second->GetId();
2688 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2689 elixir_mask |= mask;
2692 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2693 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2695 // get all available elixirs by mask and spell level
2696 std::vector<uint32> elixirs;
2697 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2698 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2700 if (itr->second & elixir_mask)
2702 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2703 continue;
2705 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2706 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2707 continue;
2709 elixirs.push_back(itr->first);
2713 if (!elixirs.empty())
2715 // cast random elixir on target
2716 uint32 rand_spell = urand(0,elixirs.size()-1);
2717 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2722 void Spell::EffectEnergisePct(uint32 i)
2724 if(!unitTarget)
2725 return;
2726 if(!unitTarget->isAlive())
2727 return;
2729 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2730 return;
2732 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2734 uint32 maxPower = unitTarget->GetMaxPower(power);
2735 if(maxPower == 0)
2736 return;
2738 uint32 gain = damage * maxPower / 100;
2739 unitTarget->ModifyPower(power, gain);
2740 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2743 void Spell::SendLoot(uint64 guid, LootType loottype)
2745 Player* player = (Player*)m_caster;
2746 if (!player)
2747 return;
2749 if (gameObjTarget)
2751 switch (gameObjTarget->GetGoType())
2753 case GAMEOBJECT_TYPE_DOOR:
2754 case GAMEOBJECT_TYPE_BUTTON:
2755 gameObjTarget->UseDoorOrButton();
2756 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2757 return;
2759 case GAMEOBJECT_TYPE_QUESTGIVER:
2760 // start or end quest
2761 player->PrepareQuestMenu(guid);
2762 player->SendPreparedQuest(guid);
2763 return;
2765 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2766 // triggering linked GO
2767 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2768 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2769 return;
2771 case GAMEOBJECT_TYPE_GOOBER:
2772 // goober_scripts can be triggered if the player don't have the quest
2773 if (gameObjTarget->GetGOInfo()->goober.eventId)
2775 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2776 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2779 // cast goober spell
2780 if (gameObjTarget->GetGOInfo()->goober.questId)
2781 ///Quest require to be active for GO using
2782 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2783 return;
2785 gameObjTarget->AddUniqueUse(player);
2786 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2788 //TODO? Objective counting called without spell check but with quest objective check
2789 // if send spell id then this line will duplicate to spell casting call (double counting)
2790 // So we or have this line and not required in quest_template have reqSpellIdN
2791 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2792 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2794 // triggering linked GO
2795 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2796 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2798 return;
2800 case GAMEOBJECT_TYPE_CHEST:
2801 // TODO: possible must be moved to loot release (in different from linked triggering)
2802 if (gameObjTarget->GetGOInfo()->chest.eventId)
2804 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2805 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2808 // triggering linked GO
2809 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2810 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2812 // Don't return, let loots been taken
2816 // Send loot
2817 player->SendLoot(guid, loottype);
2820 void Spell::EffectOpenLock(uint32 /*i*/)
2822 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2824 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2825 return;
2828 Player* player = (Player*)m_caster;
2830 LootType loottype = LOOT_CORPSE;
2831 uint32 lockId = 0;
2832 uint64 guid = 0;
2834 // Get lockId
2835 if(gameObjTarget)
2837 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2838 // Arathi Basin banner opening !
2839 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2840 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2842 //isAllowUseBattleGroundObject() already called in CanCast()
2843 // in battleground check
2844 if(BattleGround *bg = player->GetBattleGround())
2846 // check if it's correct bg
2847 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2848 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2849 return;
2852 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2854 //isAllowUseBattleGroundObject() already called in CanCast()
2855 // in battleground check
2856 if(BattleGround *bg = player->GetBattleGround())
2858 if(bg->GetTypeID() == BATTLEGROUND_EY)
2859 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2860 return;
2863 lockId = gameObjTarget->GetLockId();
2864 guid = gameObjTarget->GetGUID();
2866 else if(itemTarget)
2868 lockId = itemTarget->GetProto()->LockID;
2869 guid = itemTarget->GetGUID();
2871 else
2873 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2874 return;
2877 if(!lockId) // possible case for GO and maybe for items.
2879 SendLoot(guid, loottype);
2880 return;
2883 // Get LockInfo
2884 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2886 if (!lockInfo)
2888 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2889 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2890 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2891 return;
2894 // check key
2895 for(int i = 0; i < 5; ++i)
2897 // type==1 This means lockInfo->key[i] is an item
2898 if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i])
2900 SendLoot(guid, loottype);
2901 return;
2905 uint32 SkillId = 0;
2906 // Check and skill-up skill
2907 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2908 SkillId = m_spellInfo->EffectMiscValue[1];
2909 // pickpocketing spells
2910 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2911 SkillId = SKILL_LOCKPICKING;
2913 // skill bonus provided by casting spell (mostly item spells)
2914 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2916 uint32 reqSkillValue = lockInfo->requiredminingskill;
2918 if(lockInfo->requiredlockskill) // required pick lock skill applying
2920 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2922 SendCastResult(SPELL_FAILED_FIZZLE);
2923 return;
2926 reqSkillValue = lockInfo->requiredlockskill;
2928 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2930 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2931 return;
2934 if ( SkillId )
2936 loottype = LOOT_SKINNING;
2937 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2939 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2940 return;
2943 // update skill if really known
2944 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2945 if(SkillValue) // non only item base skill
2947 if(gameObjTarget)
2949 // Allow one skill-up until respawned
2950 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
2951 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
2952 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
2954 else if(itemTarget)
2956 // Do one skill-up
2957 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2958 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
2963 SendLoot(guid, loottype);
2966 void Spell::EffectSummonChangeItem(uint32 i)
2968 if(m_caster->GetTypeId() != TYPEID_PLAYER)
2969 return;
2971 Player *player = (Player*)m_caster;
2973 // applied only to using item
2974 if(!m_CastItem)
2975 return;
2977 // ... only to item in own inventory/bank/equip_slot
2978 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
2979 return;
2981 uint32 newitemid = m_spellInfo->EffectItemType[i];
2982 if(!newitemid)
2983 return;
2985 uint16 pos = m_CastItem->GetPos();
2987 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
2988 if( !pNewItem )
2989 return;
2991 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
2993 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
2994 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
2997 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
2999 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3000 player->DurabilityLoss(pNewItem, loosePercent);
3003 if( player->IsInventoryPos( pos ) )
3005 ItemPosCountVec dest;
3006 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3007 if( msg == EQUIP_ERR_OK )
3009 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3011 // prevent crash at access and unexpected charges counting with item update queue corrupt
3012 if(m_CastItem==m_targets.getItemTarget())
3013 m_targets.setItemTarget(NULL);
3015 m_CastItem = NULL;
3017 player->StoreItem( dest, pNewItem, true);
3018 return;
3021 else if( player->IsBankPos ( pos ) )
3023 ItemPosCountVec dest;
3024 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3025 if( msg == EQUIP_ERR_OK )
3027 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3029 // prevent crash at access and unexpected charges counting with item update queue corrupt
3030 if(m_CastItem==m_targets.getItemTarget())
3031 m_targets.setItemTarget(NULL);
3033 m_CastItem = NULL;
3035 player->BankItem( dest, pNewItem, true);
3036 return;
3039 else if( player->IsEquipmentPos ( pos ) )
3041 uint16 dest;
3042 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3043 if( msg == EQUIP_ERR_OK )
3045 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3047 // prevent crash at access and unexpected charges counting with item update queue corrupt
3048 if(m_CastItem==m_targets.getItemTarget())
3049 m_targets.setItemTarget(NULL);
3051 m_CastItem = NULL;
3053 player->EquipItem( dest, pNewItem, true);
3054 player->AutoUnequipOffhandIfNeed();
3055 return;
3059 // fail
3060 delete pNewItem;
3063 void Spell::EffectOpenSecretSafe(uint32 i)
3065 EffectOpenLock(i); //no difference for now
3068 void Spell::EffectProficiency(uint32 /*i*/)
3070 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3071 return;
3072 Player *p_target = (Player*)unitTarget;
3074 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3075 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3077 p_target->AddWeaponProficiency(subClassMask);
3078 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3080 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3082 p_target->AddArmorProficiency(subClassMask);
3083 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3087 void Spell::EffectApplyAreaAura(uint32 i)
3089 if(!unitTarget)
3090 return;
3091 if(!unitTarget->isAlive())
3092 return;
3094 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3095 unitTarget->AddAura(Aur);
3098 void Spell::EffectSummonType(uint32 i)
3100 switch(m_spellInfo->EffectMiscValueB[i])
3102 case SUMMON_TYPE_GUARDIAN:
3103 case SUMMON_TYPE_POSESSED:
3104 case SUMMON_TYPE_POSESSED2:
3105 EffectSummonGuardian(i);
3106 break;
3107 case SUMMON_TYPE_WILD:
3108 EffectSummonWild(i);
3109 break;
3110 case SUMMON_TYPE_DEMON:
3111 EffectSummonDemon(i);
3112 break;
3113 case SUMMON_TYPE_SUMMON:
3114 EffectSummon(i);
3115 break;
3116 case SUMMON_TYPE_CRITTER:
3117 case SUMMON_TYPE_CRITTER2:
3118 case SUMMON_TYPE_CRITTER3:
3119 EffectSummonCritter(i);
3120 break;
3121 case SUMMON_TYPE_TOTEM_SLOT1:
3122 case SUMMON_TYPE_TOTEM_SLOT2:
3123 case SUMMON_TYPE_TOTEM_SLOT3:
3124 case SUMMON_TYPE_TOTEM_SLOT4:
3125 case SUMMON_TYPE_TOTEM:
3126 EffectSummonTotem(i);
3127 break;
3128 case SUMMON_TYPE_UNKNOWN1:
3129 case SUMMON_TYPE_UNKNOWN2:
3130 case SUMMON_TYPE_UNKNOWN3:
3131 case SUMMON_TYPE_UNKNOWN4:
3132 case SUMMON_TYPE_UNKNOWN5:
3133 break;
3134 default:
3135 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3136 break;
3140 void Spell::EffectSummon(uint32 i)
3142 if(m_caster->GetPetGUID())
3143 return;
3145 if(!unitTarget)
3146 return;
3147 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3148 if(!pet_entry)
3149 return;
3150 uint32 level = m_caster->getLevel();
3151 Pet* spawnCreature = new Pet(SUMMON_PET);
3153 if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
3155 // set timer for unsummon
3156 int32 duration = GetSpellDuration(m_spellInfo);
3157 if(duration > 0)
3158 spawnCreature->SetDuration(duration);
3160 return;
3163 Map *map = m_caster->GetMap();
3164 uint32 pet_number = objmgr.GeneratePetNumber();
3165 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3167 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3168 delete spawnCreature;
3169 return;
3172 // Summon in dest location
3173 float x,y,z;
3174 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3176 x = m_targets.m_destX;
3177 y = m_targets.m_destY;
3178 z = m_targets.m_destZ;
3180 else
3181 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3183 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3185 if(!spawnCreature->IsPositionValid())
3187 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3188 delete spawnCreature;
3189 return;
3192 // set timer for unsummon
3193 int32 duration = GetSpellDuration(m_spellInfo);
3194 if(duration > 0)
3195 spawnCreature->SetDuration(duration);
3197 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
3198 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3199 spawnCreature->setPowerType(POWER_MANA);
3200 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3201 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3202 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
3203 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3204 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3205 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
3206 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
3207 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3208 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3210 spawnCreature->InitStatsForLevel(level);
3212 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3214 spawnCreature->AIM_Initialize();
3215 spawnCreature->InitPetCreateSpells();
3216 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3217 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3219 std::string name = m_caster->GetName();
3220 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3221 spawnCreature->SetName( name );
3223 map->Add((Creature*)spawnCreature);
3225 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3227 m_caster->SetPet(spawnCreature);
3228 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3229 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3230 ((Player*)m_caster)->PetSpellInitialize();
3234 void Spell::EffectLearnSpell(uint32 i)
3236 if(!unitTarget)
3237 return;
3239 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3241 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3242 EffectLearnPetSpell(i);
3244 return;
3247 Player *player = (Player*)unitTarget;
3249 uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i];
3250 player->learnSpell(spellToLearn);
3252 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3255 void Spell::EffectDispel(uint32 i)
3257 if(!unitTarget)
3258 return;
3260 // Fill possible dispell list
3261 std::vector <Aura *> dispel_list;
3263 // Create dispel mask by dispel type
3264 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3265 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3266 Unit::AuraMap const& auras = unitTarget->GetAuras();
3267 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3269 Aura *aur = (*itr).second;
3270 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3272 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3274 bool positive = true;
3275 if (!aur->IsPositive())
3276 positive = false;
3277 else
3278 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3280 // do not remove positive auras if friendly target
3281 // negative auras if non-friendly target
3282 if(positive == unitTarget->IsFriendlyTo(m_caster))
3283 continue;
3285 // Add aura to dispel list
3286 dispel_list.push_back(aur);
3289 // Ok if exist some buffs for dispel try dispel it
3290 if (!dispel_list.empty())
3292 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3293 std::list < uint32 > fail_list; // spell_id
3294 int32 list_size = dispel_list.size();
3295 // Dispell N = damage buffs (or while exist buffs for dispel)
3296 for (int32 count=0; count < damage && list_size > 0; ++count)
3298 // Random select buff for dispel
3299 Aura *aur = dispel_list[urand(0, list_size-1)];
3301 SpellEntry const* spellInfo = aur->GetSpellProto();
3302 // Base dispel chance
3303 // TODO: possible chance depend from spell level??
3304 int32 miss_chance = 0;
3305 // Apply dispel mod from aura caster
3306 if (Unit *caster = aur->GetCaster())
3308 if ( Player* modOwner = caster->GetSpellModOwner() )
3309 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3311 // Try dispel
3312 if (roll_chance_i(miss_chance))
3313 fail_list.push_back(aur->GetId());
3314 else
3315 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3316 // Remove buff from list for prevent doubles
3317 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3319 Aura *dispeled = *j;
3320 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3322 j = dispel_list.erase(j);
3323 --list_size;
3325 else
3326 ++j;
3329 // Send success log and really remove auras
3330 if (!success_list.empty())
3332 int32 count = success_list.size();
3333 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3334 data.append(unitTarget->GetPackGUID()); // Victim GUID
3335 data.append(m_caster->GetPackGUID()); // Caster GUID
3336 data << uint32(m_spellInfo->Id); // Dispell spell id
3337 data << uint8(0); // not used
3338 data << uint32(count); // count
3339 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3341 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3342 data << uint32(spellInfo->Id); // Spell Id
3343 data << uint8(0); // 0 - dispeled !=0 cleansed
3344 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3346 m_caster->SendMessageToSet(&data, true);
3348 // On succes dispel
3349 // Devour Magic
3350 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3352 uint32 heal_spell = 0;
3353 switch (m_spellInfo->Id)
3355 case 19505: heal_spell = 19658; break;
3356 case 19731: heal_spell = 19732; break;
3357 case 19734: heal_spell = 19733; break;
3358 case 19736: heal_spell = 19735; break;
3359 case 27276: heal_spell = 27278; break;
3360 case 27277: heal_spell = 27279; break;
3361 default:
3362 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3363 break;
3365 if (heal_spell)
3366 m_caster->CastSpell(m_caster, heal_spell, true);
3369 // Send fail log to client
3370 if (!fail_list.empty())
3372 // Failed to dispell
3373 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3374 data << uint64(m_caster->GetGUID()); // Caster GUID
3375 data << uint64(unitTarget->GetGUID()); // Victim GUID
3376 data << uint32(m_spellInfo->Id); // Dispell spell id
3377 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3378 data << uint32(*j); // Spell Id
3379 m_caster->SendMessageToSet(&data, true);
3384 void Spell::EffectDualWield(uint32 /*i*/)
3386 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
3387 ((Player*)unitTarget)->SetCanDualWield(true);
3390 void Spell::EffectPull(uint32 /*i*/)
3392 // TODO: create a proper pull towards distract spell center for distract
3393 sLog.outDebug("WORLD: Spell Effect DUMMY");
3396 void Spell::EffectDistract(uint32 /*i*/)
3398 // Check for possible target
3399 if (!unitTarget || unitTarget->isInCombat())
3400 return;
3402 // target must be OK to do this
3403 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3404 return;
3406 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3408 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3410 // For players just turn them
3411 WorldPacket data;
3412 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3413 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3414 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3416 else
3418 // Set creature Distracted, Stop it, And turn it
3419 unitTarget->SetOrientation(angle);
3420 unitTarget->StopMoving();
3421 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3425 void Spell::EffectPickPocket(uint32 /*i*/)
3427 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3428 return;
3430 // victim must be creature and attackable
3431 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3432 return;
3434 // victim have to be alive and humanoid or undead
3435 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3437 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3439 if (chance > irand(0, 19))
3441 // Stealing successful
3442 //sLog.outDebug("Sending loot from pickpocket");
3443 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3445 else
3447 // Reveal action + get attack
3448 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3449 if (((Creature*)unitTarget)->AI())
3450 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3455 void Spell::EffectAddFarsight(uint32 i)
3457 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3458 int32 duration = GetSpellDuration(m_spellInfo);
3459 DynamicObject* dynObj = new DynamicObject;
3460 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))
3462 delete dynObj;
3463 return;
3465 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3466 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3467 m_caster->AddDynObject(dynObj);
3468 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
3469 m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID());
3472 void Spell::EffectSummonWild(uint32 i)
3474 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3475 if(!creature_entry)
3476 return;
3478 uint32 level = m_caster->getLevel();
3480 // level of creature summoned using engineering item based at engineering skill level
3481 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3483 ItemPrototype const *proto = m_CastItem->GetProto();
3484 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3486 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3487 if(skill202)
3489 level = skill202/5;
3494 // select center of summon position
3495 float center_x = m_targets.m_destX;
3496 float center_y = m_targets.m_destY;
3497 float center_z = m_targets.m_destZ;
3499 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3501 int32 amount = damage > 0 ? damage : 1;
3503 for(int32 count = 0; count < amount; ++count)
3505 float px, py, pz;
3506 // If dest location if present
3507 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3509 // Summon 1 unit in dest location
3510 if (count == 0)
3512 px = m_targets.m_destX;
3513 py = m_targets.m_destY;
3514 pz = m_targets.m_destZ;
3516 // Summon in random point all other units if location present
3517 else
3518 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3520 // Summon if dest location not present near caster
3521 else
3522 m_caster->GetClosePoint(px,py,pz,3.0f);
3524 int32 duration = GetSpellDuration(m_spellInfo);
3526 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3528 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3532 void Spell::EffectSummonGuardian(uint32 i)
3534 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3535 if(!pet_entry)
3536 return;
3538 // Jewelery statue case (totem like)
3539 if(m_spellInfo->SpellIconID==2056)
3541 EffectSummonTotem(i);
3542 return;
3545 // set timer for unsummon
3546 int32 duration = GetSpellDuration(m_spellInfo);
3548 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3549 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3550 // so this code hack in fact
3551 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3552 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3553 return; // find old guardian, ignore summon
3555 // in another case summon new
3556 uint32 level = m_caster->getLevel();
3558 // level of pet summoned using engineering item based at engineering skill level
3559 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3561 ItemPrototype const *proto = m_CastItem->GetProto();
3562 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3564 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3565 if(skill202)
3567 level = skill202/5;
3572 // select center of summon position
3573 float center_x = m_targets.m_destX;
3574 float center_y = m_targets.m_destY;
3575 float center_z = m_targets.m_destZ;
3577 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3579 int32 amount = damage > 0 ? damage : 1;
3581 for(int32 count = 0; count < amount; ++count)
3583 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3585 Map *map = m_caster->GetMap();
3586 uint32 pet_number = objmgr.GeneratePetNumber();
3587 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3589 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3590 delete spawnCreature;
3591 return;
3594 float px, py, pz;
3595 // If dest location if present
3596 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3598 // Summon 1 unit in dest location
3599 if (count == 0)
3601 px = m_targets.m_destX;
3602 py = m_targets.m_destY;
3603 pz = m_targets.m_destZ;
3605 // Summon in random point all other units if location present
3606 else
3607 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3609 // Summon if dest location not present near caster
3610 else
3611 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3613 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3615 if(!spawnCreature->IsPositionValid())
3617 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3618 delete spawnCreature;
3619 return;
3622 if(duration > 0)
3623 spawnCreature->SetDuration(duration);
3625 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
3626 spawnCreature->setPowerType(POWER_MANA);
3627 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3628 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3629 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3630 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3631 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3632 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3633 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3635 spawnCreature->InitStatsForLevel(level);
3636 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3638 spawnCreature->AIM_Initialize();
3640 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3641 ((Player*)m_caster)->AddGuardian(spawnCreature);
3643 map->Add((Creature*)spawnCreature);
3647 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3649 if(!unitTarget)
3650 return;
3652 if(unitTarget->isInFlight())
3653 return;
3655 uint32 mapid = m_caster->GetMapId();
3656 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3658 float fx,fy,fz;
3659 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3661 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3662 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
3663 else
3664 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3667 void Spell::EffectLearnSkill(uint32 i)
3669 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3670 return;
3672 if(damage < 0)
3673 return;
3675 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3676 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3677 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3680 void Spell::EffectAddHonor(uint32 /*i*/)
3682 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3683 return;
3685 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow());
3687 // TODO: find formula for honor reward based on player's level!
3689 // now fixed only for level 70 players:
3690 if (((Player*)unitTarget)->getLevel() == 70)
3691 ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage);
3694 void Spell::EffectTradeSkill(uint32 /*i*/)
3696 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3697 return;
3698 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3699 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3700 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3703 void Spell::EffectEnchantItemPerm(uint32 i)
3705 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3706 return;
3707 if (!itemTarget)
3708 return;
3710 Player* p_caster = (Player*)m_caster;
3712 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3714 if (m_spellInfo->EffectMiscValue[i])
3716 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3718 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3719 if(!pEnchant)
3720 return;
3722 // item can be in trade slot and have owner diff. from caster
3723 Player* item_owner = itemTarget->GetOwner();
3724 if(!item_owner)
3725 return;
3727 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3728 sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3729 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3730 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3731 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3733 // remove old enchanting before applying new if equipped
3734 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3736 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3738 // add new enchanting if equipped
3739 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3743 void Spell::EffectEnchantItemTmp(uint32 i)
3745 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3746 return;
3748 Player* p_caster = (Player*)m_caster;
3750 if(!itemTarget)
3751 return;
3753 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3755 // Shaman Rockbiter Weapon
3756 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3758 int32 enchnting_damage = m_currentBasePoints[1]+1;
3760 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3761 // with already applied percent bonus from Elemental Weapons talent
3762 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3763 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3764 switch(enchnting_damage)
3766 // Rank 1
3767 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3768 // Rank 2
3769 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3770 case 5: enchant_id = 3025; break; // 20%
3771 // Rank 3
3772 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3773 case 7: enchant_id = 3027; break; // 20%
3774 // Rank 4
3775 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3776 case 10: enchant_id = 503; break; // 14%
3777 case 11: enchant_id = 3031; break; // 20%
3778 // Rank 5
3779 case 15: enchant_id = 3035; break; // 0%
3780 case 16: enchant_id = 1663; break; // 7%
3781 case 17: enchant_id = 3033; break; // 14%
3782 case 18: enchant_id = 3034; break; // 20%
3783 // Rank 6
3784 case 28: enchant_id = 3038; break; // 0%
3785 case 29: enchant_id = 683; break; // 7%
3786 case 31: enchant_id = 3036; break; // 14%
3787 case 33: enchant_id = 3037; break; // 20%
3788 // Rank 7
3789 case 40: enchant_id = 3041; break; // 0%
3790 case 42: enchant_id = 1664; break; // 7%
3791 case 45: enchant_id = 3039; break; // 14%
3792 case 48: enchant_id = 3040; break; // 20%
3793 // Rank 8
3794 case 49: enchant_id = 3044; break; // 0%
3795 case 52: enchant_id = 2632; break; // 7%
3796 case 55: enchant_id = 3042; break; // 14%
3797 case 58: enchant_id = 3043; break; // 20%
3798 // Rank 9
3799 case 62: enchant_id = 2633; break; // 0%
3800 case 66: enchant_id = 3018; break; // 7%
3801 case 70: enchant_id = 3019; break; // 14%
3802 case 74: enchant_id = 3020; break; // 20%
3803 default:
3804 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3805 return;
3809 if (!enchant_id)
3811 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3812 return;
3815 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3816 if(!pEnchant)
3818 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3819 return;
3822 // select enchantment duration
3823 uint32 duration;
3825 // rogue family enchantments exception by duration
3826 if(m_spellInfo->Id==38615)
3827 duration = 1800; // 30 mins
3828 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3829 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3830 duration = 3600; // 1 hour
3831 // shaman family enchantments
3832 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3833 duration = 1800; // 30 mins
3834 // other cases with this SpellVisual already selected
3835 else if(m_spellInfo->SpellVisual==215)
3836 duration = 1800; // 30 mins
3837 // some fishing pole bonuses
3838 else if(m_spellInfo->SpellVisual==563)
3839 duration = 600; // 10 mins
3840 // shaman rockbiter enchantments
3841 else if(m_spellInfo->SpellVisual==0)
3842 duration = 1800; // 30 mins
3843 else if(m_spellInfo->Id==29702)
3844 duration = 300; // 5 mins
3845 else if(m_spellInfo->Id==37360)
3846 duration = 300; // 5 mins
3847 // default case
3848 else
3849 duration = 3600; // 1 hour
3851 // item can be in trade slot and have owner diff. from caster
3852 Player* item_owner = itemTarget->GetOwner();
3853 if(!item_owner)
3854 return;
3856 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3857 sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3858 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3859 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3860 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3862 // remove old enchanting before applying new if equipped
3863 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3865 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3867 // add new enchanting if equipped
3868 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3871 void Spell::EffectTameCreature(uint32 /*i*/)
3873 if(m_caster->GetPetGUID())
3874 return;
3876 if(!unitTarget)
3877 return;
3879 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3880 return;
3882 Creature* creatureTarget = (Creature*)unitTarget;
3884 if(creatureTarget->isPet())
3885 return;
3887 if(m_caster->getClass() == CLASS_HUNTER)
3889 // cast finish successfully
3890 //SendChannelUpdate(0);
3891 finish();
3893 Pet* pet = new Pet(HUNTER_PET);
3895 if(!pet->CreateBaseAtCreature(creatureTarget))
3897 delete pet;
3898 return;
3901 creatureTarget->setDeathState(JUST_DIED);
3902 creatureTarget->RemoveCorpse();
3903 creatureTarget->SetHealth(0); // just for nice GM-mode view
3905 pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
3906 pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3907 pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3908 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3910 if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
3912 sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
3913 delete pet;
3914 return;
3917 // prepare visual effect for levelup
3918 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
3920 pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
3921 // this enables pet details window (Shift+P)
3922 pet->AIM_Initialize();
3923 pet->InitPetCreateSpells();
3924 pet->SetHealth(pet->GetMaxHealth());
3926 MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
3928 // visual effect for levelup
3929 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
3931 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3933 m_caster->SetPet(pet);
3934 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3935 ((Player*)m_caster)->PetSpellInitialize();
3940 void Spell::EffectSummonPet(uint32 i)
3942 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3944 Pet *OldSummon = m_caster->GetPet();
3946 // if pet requested type already exist
3947 if( OldSummon )
3949 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3951 // pet in corpse state can't be summoned
3952 if( OldSummon->isDead() )
3953 return;
3955 MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false);
3956 OldSummon->SetMapId(m_caster->GetMapId());
3958 float px, py, pz;
3959 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3961 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3962 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon);
3964 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
3966 ((Player*)m_caster)->PetSpellInitialize();
3968 return;
3971 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3972 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
3973 else
3974 return;
3977 Pet* NewSummon = new Pet;
3979 // petentry==0 for hunter "call pet" (current pet summoned if any)
3980 if(NewSummon->LoadPetFromDB(m_caster,petentry))
3982 if(NewSummon->getPetType()==SUMMON_PET)
3984 // Remove Demonic Sacrifice auras (known pet)
3985 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
3986 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
3988 if((*itr)->GetModifier()->m_miscvalue==2228)
3990 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
3991 itr = auraClassScripts.begin();
3993 else
3994 ++itr;
3998 return;
4001 // not error in case fail hunter call pet
4002 if(!petentry)
4004 delete NewSummon;
4005 return;
4008 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4010 if(!cInfo)
4012 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4013 delete NewSummon;
4014 return;
4017 Map *map = m_caster->GetMap();
4018 uint32 pet_number = objmgr.GeneratePetNumber();
4019 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4021 delete NewSummon;
4022 return;
4025 float px, py, pz;
4026 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4028 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4030 if(!NewSummon->IsPositionValid())
4032 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4033 delete NewSummon;
4034 return;
4037 uint32 petlevel = m_caster->getLevel();
4038 NewSummon->setPetType(SUMMON_PET);
4040 uint32 faction = m_caster->getFaction();
4041 if(m_caster->GetTypeId() == TYPEID_UNIT)
4043 if ( ((Creature*)m_caster)->isTotem() )
4044 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4045 else
4046 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4049 NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
4050 NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
4051 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0);
4052 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4053 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
4054 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
4055 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL));
4056 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
4057 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
4058 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4060 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4061 // this enables pet details window (Shift+P)
4063 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4064 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4066 NewSummon->InitStatsForLevel( petlevel);
4067 NewSummon->InitPetCreateSpells();
4069 if(NewSummon->getPetType()==SUMMON_PET)
4071 // Remove Demonic Sacrifice auras (new pet)
4072 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4073 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4075 if((*itr)->GetModifier()->m_miscvalue==2228)
4077 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4078 itr = auraClassScripts.begin();
4080 else
4081 ++itr;
4084 // generate new name for summon pet
4085 std::string new_name=objmgr.GeneratePetName(petentry);
4086 if(!new_name.empty())
4087 NewSummon->SetName(new_name);
4089 else if(NewSummon->getPetType()==HUNTER_PET)
4090 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4092 NewSummon->AIM_Initialize();
4093 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4094 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4096 map->Add((Creature*)NewSummon);
4098 m_caster->SetPet(NewSummon);
4099 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4101 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4103 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4104 ((Player*)m_caster)->PetSpellInitialize();
4108 void Spell::EffectLearnPetSpell(uint32 i)
4110 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4111 return;
4113 Player *_player = (Player*)m_caster;
4115 Pet *pet = _player->GetPet();
4116 if(!pet)
4117 return;
4118 if(!pet->isAlive())
4119 return;
4121 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4122 if(!learn_spellproto)
4123 return;
4125 pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id));
4126 pet->learnSpell(learn_spellproto->Id);
4128 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4129 _player->PetSpellInitialize();
4132 void Spell::EffectTaunt(uint32 /*i*/)
4134 // this effect use before aura Taunt apply for prevent taunt already attacking target
4135 // for spell as marked "non effective at already attacking target"
4136 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4138 if(unitTarget->getVictim()==m_caster)
4140 SendCastResult(SPELL_FAILED_DONT_REPORT);
4141 return;
4145 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4146 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4147 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4150 void Spell::EffectWeaponDmg(uint32 i)
4152 if(!unitTarget)
4153 return;
4154 if(!unitTarget->isAlive())
4155 return;
4157 // multiple weapon dmg effect workaround
4158 // execute only the last weapon damage
4159 // and handle all effects at once
4160 for (int j = 0; j < 3; j++)
4162 switch(m_spellInfo->Effect[j])
4164 case SPELL_EFFECT_WEAPON_DAMAGE:
4165 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4166 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4167 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4168 if (j < i) // we must calculate only at last weapon effect
4169 return;
4170 break;
4174 // some spell specific modifiers
4175 bool customBonusDamagePercentMod = false;
4176 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4177 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4178 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4179 bool normalized = false;
4181 int32 spell_bonus = 0; // bonus specific for spell
4182 switch(m_spellInfo->SpellFamilyName)
4184 case SPELLFAMILY_WARRIOR:
4186 // Whirlwind, single only spell with 2 weapon white damage apply if have
4187 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4189 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4190 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4192 // Devastate bonus and sunder armor refresh
4193 else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
4195 customBonusDamagePercentMod = true;
4196 bonusDamagePercentMod = 0.0f; // only applied if auras found
4198 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4199 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4201 SpellEntry const *proto = (*itr)->GetSpellProto();
4202 if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
4204 int32 duration = GetSpellDuration(proto);
4205 (*itr)->SetAuraDuration(duration);
4206 (*itr)->UpdateAuraDuration();
4207 bonusDamagePercentMod += 1.0f; // +100%
4211 break;
4213 case SPELLFAMILY_ROGUE:
4215 // Ambush
4216 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4218 customBonusDamagePercentMod = true;
4219 bonusDamagePercentMod = 2.5f; // 250%
4221 // Mutilate (for each hand)
4222 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4224 bool found = false;
4225 // fast check
4226 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4227 found = true;
4228 // full aura scan
4229 else
4231 Unit::AuraMap const& auras = unitTarget->GetAuras();
4232 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4234 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4236 found = true;
4237 break;
4242 if(found)
4243 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4245 break;
4247 case SPELLFAMILY_PALADIN:
4249 // Seal of Command - receive benefit from Spell Damage and Healing
4250 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4252 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4253 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4255 break;
4257 case SPELLFAMILY_SHAMAN:
4259 // Skyshatter Harness item set bonus
4260 // Stormstrike
4261 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4263 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4264 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4266 // Stormstrike AP Buff
4267 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4269 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4270 break;
4277 int32 fixed_bonus = 0;
4278 for (int j = 0; j < 3; j++)
4280 switch(m_spellInfo->Effect[j])
4282 case SPELL_EFFECT_WEAPON_DAMAGE:
4283 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4284 fixed_bonus += CalculateDamage(j,unitTarget);
4285 break;
4286 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4287 fixed_bonus += CalculateDamage(j,unitTarget);
4288 normalized = true;
4289 break;
4290 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4291 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4293 // applied only to prev.effects fixed damage
4294 if(customBonusDamagePercentMod)
4295 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4296 else
4297 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4298 break;
4299 default:
4300 break; // not weapon damage effect, just skip
4304 // non-weapon damage
4305 int32 bonus = spell_bonus + fixed_bonus;
4307 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4308 if(bonus)
4310 UnitMods unitMod;
4311 switch(m_attackType)
4313 default:
4314 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4315 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4316 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4319 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4320 bonus = int32(bonus*weapon_total_pct);
4323 // + weapon damage with applied weapon% dmg to base weapon damage in call
4324 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4326 // total damage
4327 bonus = int32(bonus*totalDamagePercentMod);
4329 // prevent negative damage
4330 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4332 const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
4334 uint32 hitInfo = 0;
4335 VictimState victimState = VICTIMSTATE_NORMAL;
4336 uint32 blocked_dmg = 0;
4337 uint32 absorbed_dmg = 0;
4338 uint32 resisted_dmg = 0;
4339 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
4341 m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
4343 if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
4344 m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
4346 bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
4347 m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
4349 if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
4351 eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
4353 else
4355 cleanDamage.damage += eff_damage;
4356 eff_damage = 0;
4359 // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
4360 m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
4362 // Hemorrhage
4363 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4365 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4366 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4369 // Mangle (Cat): CP
4370 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4372 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4373 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4376 // take ammo
4377 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4379 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4381 // wands don't have ammo
4382 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4383 return;
4385 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4387 if(pItem->GetMaxStackCount()==1)
4389 // decrease durability for non-stackable throw weapon
4390 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4392 else
4394 // decrease items amount for stackable throw weapon
4395 uint32 count = 1;
4396 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4399 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4400 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4404 void Spell::EffectThreat(uint32 /*i*/)
4406 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4407 return;
4409 if(!unitTarget->CanHaveThreatList())
4410 return;
4412 unitTarget->AddThreat(m_caster, float(damage));
4415 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4417 if(!unitTarget)
4418 return;
4419 if(!unitTarget->isAlive())
4420 return;
4422 uint32 heal = m_caster->GetMaxHealth();
4424 int32 gain = unitTarget->ModifyHealth(heal);
4425 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
4427 m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
4430 void Spell::EffectInterruptCast(uint32 /*i*/)
4432 if(!unitTarget)
4433 return;
4434 if(!unitTarget->isAlive())
4435 return;
4437 // TODO: not all spells that used this effect apply cooldown at school spells
4438 // also exist case: apply cooldown to interrupted cast only and to all spells
4439 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4441 if (unitTarget->m_currentSpells[i])
4443 // check if we can interrupt spell
4444 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4446 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4447 unitTarget->InterruptSpell(i,false);
4453 void Spell::EffectSummonObjectWild(uint32 i)
4455 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4457 GameObject* pGameObj = new GameObject;
4459 WorldObject* target = focusObject;
4460 if( !target )
4461 target = m_caster;
4463 float x,y,z;
4464 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4466 x = m_targets.m_destX;
4467 y = m_targets.m_destY;
4468 z = m_targets.m_destZ;
4470 else
4471 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4473 Map *map = target->GetMap();
4475 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4476 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4478 delete pGameObj;
4479 return;
4482 int32 duration = GetSpellDuration(m_spellInfo);
4483 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4484 pGameObj->SetSpellId(m_spellInfo->Id);
4486 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4487 m_caster->AddGameObject(pGameObj);
4488 map->Add(pGameObj);
4490 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4492 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4494 Player *pl = (Player*)m_caster;
4495 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4496 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4498 uint32 team = ALLIANCE;
4500 if(pl->GetTeam() == team)
4501 team = HORDE;
4503 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4508 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4510 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4512 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4513 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4515 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4520 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4522 GameObject* linkedGO = new GameObject;
4523 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4524 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4526 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4527 linkedGO->SetSpellId(m_spellInfo->Id);
4529 m_caster->AddGameObject(linkedGO);
4530 map->Add(linkedGO);
4532 else
4534 delete linkedGO;
4535 linkedGO = NULL;
4536 return;
4541 void Spell::EffectScriptEffect(uint32 effIndex)
4543 // TODO: we must implement hunter pet summon at login there (spell 6962)
4545 // by spell id
4546 switch(m_spellInfo->Id)
4548 // Bending Shinbone
4549 case 8856:
4551 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4552 return;
4554 uint32 spell_id = 0;
4555 switch(urand(1,5))
4557 case 1: spell_id = 8854; break;
4558 default: spell_id = 8855; break;
4561 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4562 return;
4565 // Healthstone creating spells
4566 case 6201:
4567 case 6202:
4568 case 5699:
4569 case 11729:
4570 case 11730:
4571 case 27230:
4573 uint32 itemtype;
4574 uint32 rank = 0;
4575 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4576 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4578 if((*i)->GetId() == 18692)
4580 rank = 1;
4581 break;
4583 else if((*i)->GetId() == 18693)
4585 rank = 2;
4586 break;
4590 static uint32 const itypes[6][3] = {
4591 { 5512,19004,19005}, // Minor Healthstone
4592 { 5511,19006,19007}, // Lesser Healthstone
4593 { 5509,19008,19009}, // Healthstone
4594 { 5510,19010,19011}, // Greater Healthstone
4595 { 9421,19012,19013}, // Major Healthstone
4596 {22103,22104,22105} // Master Healthstone
4599 switch(m_spellInfo->Id)
4601 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4602 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4603 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4604 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4605 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4606 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4607 default:
4608 return;
4610 DoCreateItem( effIndex, itemtype );
4611 return;
4613 // Brittle Armor - need remove one 24575 Brittle Armor aura
4614 case 24590:
4615 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4616 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4617 return;
4618 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4619 case 26465:
4620 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4621 return;
4622 // Orb teleport spells
4623 case 25140:
4624 case 25143:
4625 case 25650:
4626 case 25652:
4627 case 29128:
4628 case 29129:
4629 case 35376:
4630 case 35727:
4632 if(!unitTarget)
4633 return;
4635 uint32 spellid;
4636 switch(m_spellInfo->Id)
4638 case 25140: spellid = 32571; break;
4639 case 25143: spellid = 32572; break;
4640 case 25650: spellid = 30140; break;
4641 case 25652: spellid = 30141; break;
4642 case 29128: spellid = 32568; break;
4643 case 29129: spellid = 32569; break;
4644 case 35376: spellid = 25649; break;
4645 case 35727: spellid = 35730; break;
4646 default:
4647 return;
4650 unitTarget->CastSpell(unitTarget,spellid,false);
4651 return;
4654 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4655 case 22539:
4656 case 22972:
4657 case 22975:
4658 case 22976:
4659 case 22977:
4660 case 22978:
4661 case 22979:
4662 case 22980:
4663 case 22981:
4664 case 22982:
4665 case 22983:
4666 case 22984:
4667 case 22985:
4669 if(!unitTarget || !unitTarget->isAlive())
4670 return;
4672 // Onyxia Scale Cloak
4673 if(unitTarget->GetDummyAura(22683))
4674 return;
4676 // Shadow Flame
4677 m_caster->CastSpell(unitTarget, 22682, true);
4678 return;
4680 break;
4682 // Summon Black Qiraji Battle Tank
4683 case 26656:
4685 if(!unitTarget)
4686 return;
4688 // Prevent stacking of mounts
4689 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4691 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4692 if (unitTarget->GetAreaId() == 3428)
4693 unitTarget->CastSpell(unitTarget, 25863, false);
4694 else
4695 unitTarget->CastSpell(unitTarget, 26655, false);
4696 break;
4698 // Piccolo of the Flaming Fire
4699 case 17512:
4701 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4702 return;
4703 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4704 break;
4707 // Dreaming Glory
4708 case 28698:
4710 if(!unitTarget)
4711 return;
4712 unitTarget->CastSpell(unitTarget, 28694, true);
4713 break;
4716 // Netherbloom
4717 case 28702:
4719 if(!unitTarget)
4720 return;
4721 // 25% chance of casting a random buff
4722 if(roll_chance_i(75))
4723 return;
4725 // triggered spells are 28703 to 28707
4726 // Note: some sources say, that there was the possibility of
4727 // receiving a debuff. However, this seems to be removed by a patch.
4728 const uint32 spellid = 28703;
4730 // don't overwrite an existing aura
4731 for(uint8 i=0; i<5; i++)
4732 if(unitTarget->HasAura(spellid+i, 0))
4733 return;
4734 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4735 break;
4738 // Nightmare Vine
4739 case 28720:
4741 if(!unitTarget)
4742 return;
4743 // 25% chance of casting Nightmare Pollen
4744 if(roll_chance_i(75))
4745 return;
4746 unitTarget->CastSpell(unitTarget, 28721, true);
4747 break;
4750 // Mirren's Drinking Hat
4751 case 29830:
4753 uint32 item = 0;
4754 switch ( urand(1,6) )
4756 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4757 case 4: case 5: item = 23585; break;// Stouthammer Lite
4758 case 6: item = 23586; break;// Aerie Peak Pale Ale
4760 if (item)
4761 DoCreateItem(effIndex,item);
4762 break;
4764 // Improved Sprint
4765 case 30918:
4767 // Removes snares and roots.
4768 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4769 Unit::AuraMap& Auras = unitTarget->GetAuras();
4770 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4772 next = iter;
4773 ++next;
4774 Aura *aur = iter->second;
4775 if (!aur->IsPositive()) //only remove negative spells
4777 // check for mechanic mask
4778 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4780 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4781 if(Auras.empty())
4782 break;
4783 else
4784 next = Auras.begin();
4788 break;
4790 case 41126: // Flame Crash
4792 if(!unitTarget)
4793 return;
4795 unitTarget->CastSpell(unitTarget, 41131, true);
4796 break;
4798 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4800 if(!unitTarget)
4801 return;
4803 unitTarget->CastSpell(unitTarget, 44870, true);
4804 break;
4807 // Goblin Weather Machine
4808 case 46203:
4810 if(!unitTarget)
4811 return;
4813 uint32 spellId;
4814 switch(rand()%4)
4816 case 0:
4817 spellId=46740;
4818 break;
4819 case 1:
4820 spellId=46739;
4821 break;
4822 case 2:
4823 spellId=46738;
4824 break;
4825 case 3:
4826 spellId=46736;
4827 break;
4829 unitTarget->CastSpell(unitTarget, spellId, true);
4830 break;
4832 //5,000 Gold
4833 case 46642:
4835 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4836 return;
4838 ((Player*)unitTarget)->ModifyMoney(50000000);
4840 break;
4844 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4846 switch(m_spellInfo->SpellFamilyFlags)
4848 // Judgement
4849 case 0x800000:
4851 if(!unitTarget || !unitTarget->isAlive())
4852 return;
4853 uint32 spellId2 = 0;
4855 // all seals have aura dummy
4856 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4857 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4859 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4861 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4862 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4863 continue;
4865 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4866 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4868 if(spellId2 <= 1)
4869 continue;
4871 // found, remove seal
4872 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4874 // Sanctified Judgement
4875 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4876 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4878 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4880 int32 chance = (*i)->GetModifier()->m_amount;
4881 if ( roll_chance_i(chance) )
4883 int32 mana = spellInfo->manaCost;
4884 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4885 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4886 mana = int32(mana* 0.8f);
4887 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4889 break;
4893 break;
4896 m_caster->CastSpell(unitTarget,spellId2,true);
4897 return;
4902 // normal DB scripted effect
4903 if(!unitTarget)
4904 return;
4906 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
4907 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
4910 void Spell::EffectSanctuary(uint32 /*i*/)
4912 if(!unitTarget)
4913 return;
4914 //unitTarget->CombatStop();
4916 unitTarget->CombatStop();
4917 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
4918 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4919 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
4921 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4925 void Spell::EffectAddComboPoints(uint32 /*i*/)
4927 if(!unitTarget)
4928 return;
4930 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4931 return;
4933 if(damage <= 0)
4934 return;
4936 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
4939 void Spell::EffectDuel(uint32 i)
4941 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4942 return;
4944 Player *caster = (Player*)m_caster;
4945 Player *target = (Player*)unitTarget;
4947 // caster or target already have requested duel
4948 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
4949 return;
4951 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4952 // Don't have to check the target's map since you cannot challenge someone across maps
4953 if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530)
4955 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4956 return;
4959 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
4960 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
4962 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4963 return;
4966 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
4967 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
4969 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4970 return;
4973 //CREATE DUEL FLAG OBJECT
4974 GameObject* pGameObj = new GameObject;
4976 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4978 Map *map = m_caster->GetMap();
4979 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4980 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
4981 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
4982 m_caster->GetPositionZ(),
4983 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
4985 delete pGameObj;
4986 return;
4989 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
4990 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
4991 int32 duration = GetSpellDuration(m_spellInfo);
4992 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4993 pGameObj->SetSpellId(m_spellInfo->Id);
4995 m_caster->AddGameObject(pGameObj);
4996 map->Add(pGameObj);
4997 //END
4999 // Send request
5000 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5001 data << pGameObj->GetGUID();
5002 data << caster->GetGUID();
5003 caster->GetSession()->SendPacket(&data);
5004 target->GetSession()->SendPacket(&data);
5006 // create duel-info
5007 DuelInfo *duel = new DuelInfo;
5008 duel->initiator = caster;
5009 duel->opponent = target;
5010 duel->startTime = 0;
5011 duel->startTimer = 0;
5012 caster->duel = duel;
5014 DuelInfo *duel2 = new DuelInfo;
5015 duel2->initiator = caster;
5016 duel2->opponent = caster;
5017 duel2->startTime = 0;
5018 duel2->startTimer = 0;
5019 target->duel = duel2;
5021 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5022 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5025 void Spell::EffectStuck(uint32 /*i*/)
5027 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5028 return;
5030 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5031 return;
5033 Player* pTarget = (Player*)unitTarget;
5035 sLog.outDebug("Spell Effect: Stuck");
5036 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());
5038 if(pTarget->isInFlight())
5039 return;
5041 // homebind location is loaded always
5042 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5044 // Stuck spell trigger Hearthstone cooldown
5045 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5046 if(!spellInfo)
5047 return;
5048 Spell spell(pTarget,spellInfo,true,0);
5049 spell.SendSpellCooldown();
5052 void Spell::EffectSummonPlayer(uint32 /*i*/)
5054 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5055 return;
5057 // Evil Twin (ignore player summon, but hide this for summoner)
5058 if(unitTarget->GetDummyAura(23445))
5059 return;
5061 float x,y,z;
5062 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5064 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5066 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5067 data << uint64(m_caster->GetGUID()); // summoner guid
5068 data << uint32(m_caster->GetZoneId()); // summoner zone
5069 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5070 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5073 static ScriptInfo generateActivateCommand()
5075 ScriptInfo si;
5076 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5077 return si;
5080 void Spell::EffectActivateObject(uint32 effect_idx)
5082 if(!gameObjTarget)
5083 return;
5085 static ScriptInfo activateCommand = generateActivateCommand();
5087 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5089 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5092 void Spell::EffectSummonTotem(uint32 i)
5094 uint8 slot = 0;
5095 switch(m_spellInfo->EffectMiscValueB[i])
5097 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5098 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5099 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5100 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5101 // Battle standard case
5102 case SUMMON_TYPE_TOTEM: slot = 254; break;
5103 // jewelery statue case, like totem without slot
5104 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5105 default: return;
5108 if(slot < MAX_TOTEM)
5110 uint64 guid = m_caster->m_TotemSlot[slot];
5111 if(guid != 0)
5113 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5114 if(OldTotem && OldTotem->isTotem())
5115 ((Totem*)OldTotem)->UnSummon();
5119 uint32 team = 0;
5120 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5121 team = ((Player*)m_caster)->GetTeam();
5123 Totem* pTotem = new Totem;
5125 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5127 delete pTotem;
5128 return;
5131 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5133 float x,y,z;
5134 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5136 // totem must be at same Z in case swimming caster and etc.
5137 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5138 z = m_caster->GetPositionZ();
5140 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5142 if(slot < MAX_TOTEM)
5143 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5145 pTotem->SetOwner(m_caster->GetGUID());
5146 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5148 int32 duration=GetSpellDuration(m_spellInfo);
5149 if(Player* modOwner = m_caster->GetSpellModOwner())
5150 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5151 pTotem->SetDuration(duration);
5153 if (damage) // if not spell info, DB values used
5155 pTotem->SetMaxHealth(damage);
5156 pTotem->SetHealth(damage);
5159 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5160 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5162 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5163 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5165 pTotem->Summon(m_caster);
5167 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5169 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5170 data << uint8(slot);
5171 data << uint64(pTotem->GetGUID());
5172 data << uint32(duration);
5173 data << uint32(m_spellInfo->Id);
5174 ((Player*)m_caster)->SendDirectMessage(&data);
5178 void Spell::EffectEnchantHeldItem(uint32 i)
5180 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5181 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5182 return;
5184 Player* item_owner = (Player*)unitTarget;
5185 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5187 if(!item )
5188 return;
5190 // must be equipped
5191 if(!item ->IsEquipped())
5192 return;
5194 if (m_spellInfo->EffectMiscValue[i])
5196 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5197 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5198 if(!duration)
5199 duration = m_currentBasePoints[i]+1; //Base points after ..
5200 if(!duration)
5201 duration = 10; //10 seconds for enchants which don't have listed duration
5203 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5204 if(!pEnchant)
5205 return;
5207 // Always go to temp enchantment slot
5208 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5210 // Enchantment will not be applied if a different one already exists
5211 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5212 return;
5214 // Apply the temporary enchantment
5215 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5216 item_owner->ApplyEnchantment(item,slot,true);
5220 void Spell::EffectDisEnchant(uint32 /*i*/)
5222 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5223 return;
5225 Player* p_caster = (Player*)m_caster;
5226 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5227 return;
5229 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5231 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5233 // item will be removed at disenchanting end
5236 void Spell::EffectInebriate(uint32 /*i*/)
5238 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5239 return;
5241 Player *player = (Player*)unitTarget;
5242 uint16 currentDrunk = player->GetDrunkValue();
5243 uint16 drunkMod = damage * 256;
5244 if (currentDrunk + drunkMod > 0xFFFF)
5245 currentDrunk = 0xFFFF;
5246 else
5247 currentDrunk += drunkMod;
5248 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5251 void Spell::EffectFeedPet(uint32 i)
5253 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5254 return;
5256 Player *_player = (Player*)m_caster;
5258 if(!itemTarget)
5259 return;
5261 Pet *pet = _player->GetPet();
5262 if(!pet)
5263 return;
5265 if(!pet->isAlive())
5266 return;
5268 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5269 if(benefit <= 0)
5270 return;
5272 uint32 count = 1;
5273 _player->DestroyItemCount(itemTarget,count,true);
5274 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5276 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5279 void Spell::EffectDismissPet(uint32 /*i*/)
5281 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5282 return;
5284 Pet* pet = m_caster->GetPet();
5286 // not let dismiss dead pet
5287 if(!pet||!pet->isAlive())
5288 return;
5290 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5293 void Spell::EffectSummonObject(uint32 i)
5295 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5297 uint8 slot = 0;
5298 switch(m_spellInfo->Effect[i])
5300 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5301 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5302 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5303 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5304 default: return;
5307 uint64 guid = m_caster->m_ObjectSlot[slot];
5308 if(guid != 0)
5310 GameObject* obj = NULL;
5311 if( m_caster )
5312 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5314 if(obj) obj->Delete();
5315 m_caster->m_ObjectSlot[slot] = 0;
5318 GameObject* pGameObj = new GameObject;
5320 float rot2 = sin(m_caster->GetOrientation()/2);
5321 float rot3 = cos(m_caster->GetOrientation()/2);
5323 float x,y,z;
5324 // If dest location if present
5325 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5327 x = m_targets.m_destX;
5328 y = m_targets.m_destY;
5329 z = m_targets.m_destZ;
5331 // Summon in random point all other units if location present
5332 else
5333 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5335 Map *map = m_caster->GetMap();
5336 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5338 delete pGameObj;
5339 return;
5342 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5343 int32 duration = GetSpellDuration(m_spellInfo);
5344 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5345 pGameObj->SetSpellId(m_spellInfo->Id);
5346 m_caster->AddGameObject(pGameObj);
5348 map->Add(pGameObj);
5349 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5350 data << pGameObj->GetGUID();
5351 m_caster->SendMessageToSet(&data,true);
5353 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5356 void Spell::EffectResurrect(uint32 i)
5358 if(!unitTarget)
5359 return;
5360 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5361 return;
5363 if(unitTarget->isAlive())
5364 return;
5365 if(!unitTarget->IsInWorld())
5366 return;
5368 switch (m_spellInfo->Id)
5370 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5371 case 8342:
5372 if (roll_chance_i(67))
5374 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5375 return;
5377 break;
5378 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5379 case 22999:
5380 if (roll_chance_i(50))
5382 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5383 return;
5385 break;
5386 default:
5387 break;
5390 Player* pTarget = ((Player*)unitTarget);
5392 if(pTarget->isRessurectRequested()) // already have one active request
5393 return;
5395 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5396 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5398 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5399 SendResurrectRequest(pTarget);
5402 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5404 if(!unitTarget || !unitTarget->isAlive())
5405 return;
5407 if( unitTarget->m_extraAttacks )
5408 return;
5410 unitTarget->m_extraAttacks = damage;
5413 void Spell::EffectParry(uint32 /*i*/)
5415 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5417 ((Player*)unitTarget)->SetCanParry(true);
5421 void Spell::EffectBlock(uint32 /*i*/)
5423 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5424 return;
5426 ((Player*)unitTarget)->SetCanBlock(true);
5429 void Spell::EffectMomentMove(uint32 i)
5431 if(unitTarget->isInFlight())
5432 return;
5434 if( m_spellInfo->rangeIndex== 1) //self range
5436 uint32 mapid = m_caster->GetMapId();
5437 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5439 // before caster
5440 float fx,fy,fz;
5441 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5442 float ox,oy,oz;
5443 unitTarget->GetPosition(ox,oy,oz);
5445 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5446 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5448 fx = fx2;
5449 fy = fy2;
5450 fz = fz2;
5451 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5454 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5455 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5456 else
5457 MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5461 void Spell::EffectReputation(uint32 i)
5463 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5464 return;
5466 Player *_player = (Player*)unitTarget;
5468 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5470 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5472 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5474 if(!factionEntry)
5475 return;
5477 _player->ModifyFactionReputation(factionEntry,rep_change);
5480 void Spell::EffectQuestComplete(uint32 i)
5482 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5483 return;
5485 Player *_player = (Player*)m_caster;
5487 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5488 _player->AreaExploredOrEventHappens(quest_id);
5491 void Spell::EffectSelfResurrect(uint32 i)
5493 if(!unitTarget || unitTarget->isAlive())
5494 return;
5495 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5496 return;
5497 if(!unitTarget->IsInWorld())
5498 return;
5500 uint32 health = 0;
5501 uint32 mana = 0;
5503 // flat case
5504 if(damage < 0)
5506 health = uint32(-damage);
5507 mana = m_spellInfo->EffectMiscValue[i];
5509 // percent case
5510 else
5512 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5513 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5514 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5517 Player *plr = ((Player*)unitTarget);
5518 plr->ResurrectPlayer(0.0f);
5520 plr->SetHealth( health );
5521 plr->SetPower(POWER_MANA, mana );
5522 plr->SetPower(POWER_RAGE, 0 );
5523 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5525 plr->SpawnCorpseBones();
5527 plr->SaveToDB();
5530 void Spell::EffectSkinning(uint32 /*i*/)
5532 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5533 return;
5534 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5535 return;
5537 Creature* creature = (Creature*) unitTarget;
5538 int32 targetLevel = creature->getLevel();
5540 uint32 skill;
5541 if(creature->GetCreatureInfo()->flag1 & 256)
5542 skill = SKILL_HERBALISM; // special case
5543 else if(creature->GetCreatureInfo()->flag1 & 512)
5544 skill = SKILL_MINING; // special case
5545 else
5546 skill = SKILL_SKINNING; // normal case
5548 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5549 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5551 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5553 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5555 // Double chances for elites
5556 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5559 void Spell::EffectCharge(uint32 /*i*/)
5561 if(!unitTarget || !m_caster)
5562 return;
5564 float x, y, z;
5565 unitTarget->GetContactPoint(m_caster, x, y, z);
5566 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5567 ((Creature *)unitTarget)->StopMoving();
5569 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5570 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5572 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5573 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5575 // not all charge effects used in negative spells
5576 if ( !IsPositiveSpell(m_spellInfo->Id))
5577 m_caster->Attack(unitTarget,true);
5580 void Spell::EffectSummonCritter(uint32 i)
5582 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5583 return;
5584 Player* player = (Player*)m_caster;
5586 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5587 if(!pet_entry)
5588 return;
5590 Pet* old_critter = player->GetMiniPet();
5592 // for same pet just despawn
5593 if(old_critter && old_critter->GetEntry() == pet_entry)
5595 player->RemoveMiniPet();
5596 return;
5599 // despawn old pet before summon new
5600 if(old_critter)
5601 player->RemoveMiniPet();
5603 // summon new pet
5604 Pet* critter = new Pet(MINI_PET);
5606 Map *map = m_caster->GetMap();
5607 uint32 pet_number = objmgr.GeneratePetNumber();
5608 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5609 map, pet_entry, pet_number))
5611 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5612 delete critter;
5613 return;
5616 float x,y,z;
5617 // If dest location if present
5618 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5620 x = m_targets.m_destX;
5621 y = m_targets.m_destY;
5622 z = m_targets.m_destZ;
5624 // Summon if dest location not present near caster
5625 else
5626 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5628 critter->Relocate(x,y,z,m_caster->GetOrientation());
5630 if(!critter->IsPositionValid())
5632 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5633 delete critter;
5634 return;
5637 critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
5638 critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID());
5639 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5640 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5642 critter->AIM_Initialize();
5643 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5644 critter->SetMaxHealth(1);
5645 critter->SetHealth(1);
5646 critter->SetLevel(1);
5648 // set timer for unsummon
5649 int32 duration = GetSpellDuration(m_spellInfo);
5650 if(duration > 0)
5651 critter->SetDuration(duration);
5653 std::string name = player->GetName();
5654 name.append(petTypeSuffix[critter->getPetType()]);
5655 critter->SetName( name );
5656 player->SetMiniPet(critter);
5658 map->Add((Creature*)critter);
5661 void Spell::EffectKnockBack(uint32 i)
5663 if(!unitTarget || !m_caster)
5664 return;
5666 // Effect only works on players
5667 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5668 return;
5670 float vsin = sin(m_caster->GetAngle(unitTarget));
5671 float vcos = cos(m_caster->GetAngle(unitTarget));
5673 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5674 data.append(unitTarget->GetPackGUID());
5675 data << uint32(0); // Sequence
5676 data << float(vcos); // x direction
5677 data << float(vsin); // y direction
5678 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5679 data << float(damage/-10); // Z Movement speed (vertical)
5681 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5684 void Spell::EffectSendTaxi(uint32 i)
5686 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5687 return;
5689 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5690 if(!entry)
5691 return;
5693 std::vector<uint32> nodes;
5695 nodes.resize(2);
5696 nodes[0] = entry->from;
5697 nodes[1] = entry->to;
5699 uint32 mountid = 0;
5700 switch(m_spellInfo->Id)
5702 case 31606: //Stormcrow Amulet
5703 mountid = 17447;
5704 break;
5705 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5706 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5707 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5708 mountid = 22840;
5709 break;
5710 case 34905: //Stealth Flight
5711 mountid = 6851;
5712 break;
5715 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5719 void Spell::EffectPlayerPull(uint32 i)
5721 if(!unitTarget || !m_caster)
5722 return;
5724 // Effect only works on players
5725 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5726 return;
5728 float vsin = sin(unitTarget->GetAngle(m_caster));
5729 float vcos = cos(unitTarget->GetAngle(m_caster));
5731 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5732 data.append(unitTarget->GetPackGUID());
5733 data << uint32(0); // Sequence
5734 data << float(vcos); // x direction
5735 data << float(vsin); // y direction
5736 // Horizontal speed
5737 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5738 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5740 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5743 void Spell::EffectDispelMechanic(uint32 i)
5745 if(!unitTarget)
5746 return;
5748 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5750 Unit::AuraMap& Auras = unitTarget->GetAuras();
5751 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5753 next = iter;
5754 ++next;
5755 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5756 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5758 unitTarget->RemoveAurasDueToSpell(spell->Id);
5759 if(Auras.empty())
5760 break;
5761 else
5762 next = Auras.begin();
5765 return;
5768 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5770 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5771 return;
5772 Player *_player = (Player*)m_caster;
5773 Pet *pet = _player->GetPet();
5774 if(!pet)
5775 return;
5776 if(pet->isAlive())
5777 return;
5778 if(damage < 0)
5779 return;
5780 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5781 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5782 pet->setDeathState( ALIVE );
5783 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5784 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5786 pet->AIM_Initialize();
5788 _player->PetSpellInitialize();
5789 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5792 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5794 float mana = 0;
5795 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5797 if(!m_caster->m_TotemSlot[slot])
5798 continue;
5800 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5801 if(totem && totem->isTotem())
5803 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5804 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5805 if(spellInfo)
5806 mana += spellInfo->manaCost * damage / 100;
5807 ((Totem*)totem)->UnSummon();
5811 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5812 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5815 void Spell::EffectDurabilityDamage(uint32 i)
5817 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5818 return;
5820 int32 slot = m_spellInfo->EffectMiscValue[i];
5822 // FIXME: some spells effects have value -1/-2
5823 // Possibly its mean -1 all player equipped items and -2 all items
5824 if(slot < 0)
5826 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5827 return;
5830 // invalid slot value
5831 if(slot >= INVENTORY_SLOT_BAG_END)
5832 return;
5834 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5835 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5838 void Spell::EffectDurabilityDamagePCT(uint32 i)
5840 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5841 return;
5843 int32 slot = m_spellInfo->EffectMiscValue[i];
5845 // FIXME: some spells effects have value -1/-2
5846 // Possibly its mean -1 all player equipped items and -2 all items
5847 if(slot < 0)
5849 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5850 return;
5853 // invalid slot value
5854 if(slot >= INVENTORY_SLOT_BAG_END)
5855 return;
5857 if(damage <= 0)
5858 return;
5860 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5861 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
5864 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
5866 if(!unitTarget)
5867 return;
5869 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5872 void Spell::EffectTransmitted(uint32 effIndex)
5874 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
5876 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
5878 if (!goinfo)
5880 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
5881 return;
5884 float fx,fy,fz;
5886 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5888 fx = m_targets.m_destX;
5889 fy = m_targets.m_destY;
5890 fz = m_targets.m_destZ;
5892 //FIXME: this can be better check for most objects but still hack
5893 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
5895 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
5896 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5898 else
5900 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5901 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5902 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
5904 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5907 Map *cMap = m_caster->GetMap();
5909 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
5911 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
5912 { // but this is not proper, we really need to ignore not materialized objects
5913 SendCastResult(SPELL_FAILED_NOT_HERE);
5914 SendChannelUpdate(0);
5915 return;
5918 // replace by water level in this case
5919 fz = cMap->GetWaterLevel(fx,fy);
5921 // if gameobject is summoning object, it should be spawned right on caster's position
5922 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5924 m_caster->GetPosition(fx,fy,fz);
5927 GameObject* pGameObj = new GameObject;
5929 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5930 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5932 delete pGameObj;
5933 return;
5936 int32 duration = GetSpellDuration(m_spellInfo);
5938 switch(goinfo->type)
5940 case GAMEOBJECT_TYPE_FISHINGNODE:
5942 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
5943 // Orientation3
5944 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 );
5945 // Orientation4
5946 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 );
5947 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5949 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5950 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5951 int32 lastSec;
5952 switch(urand(0, 3))
5954 case 0: lastSec = 3; break;
5955 case 1: lastSec = 7; break;
5956 case 2: lastSec = 13; break;
5957 case 3: lastSec = 17; break;
5960 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
5961 break;
5963 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
5965 if(m_caster->GetTypeId()==TYPEID_PLAYER)
5967 pGameObj->AddUniqueUse((Player*)m_caster);
5968 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5970 break;
5972 case GAMEOBJECT_TYPE_FISHINGHOLE:
5973 case GAMEOBJECT_TYPE_CHEST:
5974 default:
5976 break;
5980 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5982 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
5984 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
5985 pGameObj->SetSpellId(m_spellInfo->Id);
5987 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
5988 //m_caster->AddGameObject(pGameObj);
5989 //m_ObjToDel.push_back(pGameObj);
5991 cMap->Add(pGameObj);
5993 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5994 data << uint64(pGameObj->GetGUID());
5995 m_caster->SendMessageToSet(&data,true);
5997 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
5999 GameObject* linkedGO = new GameObject;
6000 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6001 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6003 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6004 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6005 linkedGO->SetSpellId(m_spellInfo->Id);
6006 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6008 MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->Add(linkedGO);
6010 else
6012 delete linkedGO;
6013 linkedGO = NULL;
6014 return;
6019 void Spell::EffectProspecting(uint32 /*i*/)
6021 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6022 return;
6024 Player* p_caster = (Player*)m_caster;
6025 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6026 return;
6028 if(itemTarget->GetCount() < 5)
6029 return;
6031 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6033 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6034 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6035 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6038 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6041 void Spell::EffectSkill(uint32 /*i*/)
6043 sLog.outDebug("WORLD: SkillEFFECT");
6046 void Spell::EffectSummonDemon(uint32 i)
6048 float px = m_targets.m_destX;
6049 float py = m_targets.m_destY;
6050 float pz = m_targets.m_destZ;
6052 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6053 if (!Charmed)
6054 return;
6056 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6057 Charmed->SetLevel(m_caster->getLevel());
6059 // TODO: Add damage/mana/hp according to level
6061 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6063 // Enslave demon effect, without mana cost and cooldown
6064 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6066 // Inferno effect
6067 Charmed->CastSpell(Charmed, 22703, true, 0);
6071 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6072 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6073 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6074 This is why we use a half sec delay between the visual effect and the resurrection itself */
6075 void Spell::EffectSpiritHeal(uint32 /*i*/)
6078 if(!unitTarget || unitTarget->isAlive())
6079 return;
6080 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6081 return;
6082 if(!unitTarget->IsInWorld())
6083 return;
6085 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6086 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6087 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6088 ((Player*)unitTarget)->SpawnCorpseBones();
6092 // remove insignia spell effect
6093 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6095 sLog.outDebug("Effect: SkinPlayerCorpse");
6096 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6097 return;
6099 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6102 void Spell::EffectStealBeneficialBuff(uint32 i)
6104 sLog.outDebug("Effect: StealBeneficialBuff");
6106 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6107 return;
6109 std::vector <Aura *> steal_list;
6110 // Create dispel mask by dispel type
6111 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6112 Unit::AuraMap const& auras = unitTarget->GetAuras();
6113 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6115 Aura *aur = (*itr).second;
6116 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6118 // Need check for passive? this
6119 if (aur->IsPositive() && !aur->IsPassive())
6120 steal_list.push_back(aur);
6123 // Ok if exist some buffs for dispel try dispel it
6124 if (!steal_list.empty())
6126 std::list < std::pair<uint32,uint64> > success_list;
6127 int32 list_size = steal_list.size();
6128 // Dispell N = damage buffs (or while exist buffs for dispel)
6129 for (int32 count=0; count < damage && list_size > 0; ++count)
6131 // Random select buff for dispel
6132 Aura *aur = steal_list[urand(0, list_size-1)];
6133 // Not use chance for steal
6134 // TODO possible need do it
6135 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6137 // Remove buff from list for prevent doubles
6138 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6140 Aura *stealed = *j;
6141 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6143 j = steal_list.erase(j);
6144 --list_size;
6146 else
6147 ++j;
6150 // Really try steal and send log
6151 if (!success_list.empty())
6153 int32 count = success_list.size();
6154 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6155 data.append(unitTarget->GetPackGUID()); // Victim GUID
6156 data.append(m_caster->GetPackGUID()); // Caster GUID
6157 data << uint32(m_spellInfo->Id); // Dispell spell id
6158 data << uint8(0); // not used
6159 data << uint32(count); // count
6160 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6162 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6163 data << uint32(spellInfo->Id); // Spell Id
6164 data << uint8(0); // 0 - steals !=0 transfers
6165 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6167 m_caster->SendMessageToSet(&data, true);
6172 void Spell::EffectKillCredit(uint32 i)
6174 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6175 return;
6177 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6180 void Spell::EffectQuestFail(uint32 i)
6182 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6183 return;
6185 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);