Updated vmap extractor bin's
[getmangos.git] / src / game / SpellEffects.cpp
blobe39a16c4f941159279acc2a083ba18a34fc4c2a5
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::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
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::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
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
213 &Spell::EffectNULL, //154 unused
214 &Spell::EffectNULL, //155 Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
215 &Spell::EffectNULL, //156 Add Socket
216 &Spell::EffectNULL, //157 create/learn random item/spell for profession
217 &Spell::EffectNULL, //158 milling
218 &Spell::EffectNULL //159 allow rename pet once again
221 void Spell::EffectNULL(uint32 /*i*/)
223 sLog.outDebug("WORLD: Spell Effect DUMMY");
226 void Spell::EffectUnused(uint32 /*i*/)
228 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
231 void Spell::EffectResurrectNew(uint32 i)
233 if(!unitTarget || unitTarget->isAlive())
234 return;
236 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
237 return;
239 if(!unitTarget->IsInWorld())
240 return;
242 Player* pTarget = ((Player*)unitTarget);
244 if(pTarget->isRessurectRequested()) // already have one active request
245 return;
247 uint32 health = damage;
248 uint32 mana = m_spellInfo->EffectMiscValue[i];
249 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
250 SendResurrectRequest(pTarget);
253 void Spell::EffectInstaKill(uint32 /*i*/)
255 if( !unitTarget || !unitTarget->isAlive() )
256 return;
258 // Demonic Sacrifice
259 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
261 uint32 entry = unitTarget->GetEntry();
262 uint32 spellID;
263 switch(entry)
265 case 416: spellID=18789; break; //imp
266 case 417: spellID=18792; break; //fellhunter
267 case 1860: spellID=18790; break; //void
268 case 1863: spellID=18791; break; //succubus
269 case 17252: spellID=35701; break; //fellguard
270 default:
271 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
272 return;
275 m_caster->CastSpell(m_caster,spellID,true);
278 if(m_caster==unitTarget) // prevent interrupt message
279 finish();
281 uint32 health = unitTarget->GetHealth();
282 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
285 void Spell::EffectEnvirinmentalDMG(uint32 i)
287 uint32 absorb = 0;
288 uint32 resist = 0;
290 // Note: this hack with damage replace required until GO casting not implemented
291 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
292 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
293 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
295 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
297 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
298 if(m_caster->GetTypeId() == TYPEID_PLAYER)
299 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
302 void Spell::EffectSchoolDMG(uint32 effect_idx)
304 if( unitTarget && unitTarget->isAlive())
306 switch(m_spellInfo->SpellFamilyName)
308 case SPELLFAMILY_GENERIC:
310 //Gore
311 if(m_spellInfo->SpellIconID == 2269 )
313 damage+= rand()%2 ? damage : 0;
316 switch(m_spellInfo->Id) // better way to check unknown
318 // Meteor like spells (divided damage to targets)
319 case 24340: case 26558: case 28884: // Meteor
320 case 36837: case 38903: case 41276: // Meteor
321 case 26789: // Shard of the Fallen Star
322 case 31436: // Malevolent Cleave
323 case 35181: // Dive Bomb
324 case 40810: case 43267: case 43268: // Saber Lash
325 case 42384: // Brutal Swipe
326 case 45150: // Meteor Slash
328 uint32 count = 0;
329 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
330 if(ihit->effectMask & (1<<effect_idx))
331 ++count;
333 damage /= count; // divide to all targets
334 break;
336 // percent from health with min
337 case 25599: // Thundercrash
339 damage = unitTarget->GetHealth() / 2;
340 if(damage < 200)
341 damage = 200;
342 break;
345 break;
348 case SPELLFAMILY_MAGE:
350 // Arcane Blast
351 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
353 m_caster->CastSpell(m_caster,36032,true);
355 break;
357 case SPELLFAMILY_WARRIOR:
359 // Bloodthirst
360 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
362 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
364 // Shield Slam
365 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
366 damage += int32(m_caster->GetShieldBlockValue());
367 // Victory Rush
368 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
370 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
371 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
373 break;
375 case SPELLFAMILY_WARLOCK:
377 // Incinerate Rank 1 & 2
378 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
380 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
381 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
382 damage += int32(damage*0.25);
384 break;
386 case SPELLFAMILY_DRUID:
388 // Ferocious Bite
389 if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
391 // converts each extra point of energy into ($f1+$AP/630) additional damage
392 float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
393 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
394 m_caster->SetPower(POWER_ENERGY,0);
396 // Rake
397 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
399 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
401 // Swipe
402 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
404 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
406 // Starfire
407 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
409 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
410 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
412 // Starfire Bonus (caster)
413 switch((*i)->GetModifier()->m_miscvalue)
415 case 5481: // Nordrassil Regalia - bonus
417 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
418 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
420 // Moonfire or Insect Swarm (target debuff from any casters)
421 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
423 int32 mod = (*i)->GetModifier()->m_amount;
424 damage += damage*mod/100;
425 break;
428 break;
430 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
432 damage += (*i)->GetModifier()->m_amount;
433 break;
438 //Mangle Bonus for the initial damage of Lacerate and Rake
439 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
440 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
442 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
443 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
444 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
446 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
447 break;
450 break;
452 case SPELLFAMILY_ROGUE:
454 // Envenom
455 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
457 // consume from stack dozes not more that have combo-points
458 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
460 // count consumed deadly poison doses at target
461 uint32 doses = 0;
463 // remove consumed poison doses
464 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
465 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
467 // Deadly poison (only attacker applied)
468 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
469 (*itr)->GetSpellProto()->SpellVisual[0]==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
471 --combo;
472 ++doses;
474 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
476 itr = auras.begin();
478 else
479 ++itr;
482 damage *= doses;
483 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
485 // Eviscerate and Envenom Bonus Damage (item set effect)
486 if(m_caster->GetDummyAura(37169))
487 damage += ((Player*)m_caster)->GetComboPoints()*40;
490 // Eviscerate
491 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
493 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
495 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
497 // Eviscerate and Envenom Bonus Damage (item set effect)
498 if(m_caster->GetDummyAura(37169))
499 damage += combo*40;
502 break;
504 case SPELLFAMILY_HUNTER:
506 // Mongoose Bite
507 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
509 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
511 // Arcane Shot
512 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
514 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
516 // Steady Shot
517 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
519 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
520 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
522 //Explosive Trap Effect
523 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
525 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
527 break;
529 case SPELLFAMILY_PALADIN:
531 //Judgement of Vengeance
532 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
534 uint32 stacks = 0;
535 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
536 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
537 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
538 ++stacks;
539 if(!stacks)
540 //No damage if the target isn't affected by this
541 damage = -1;
542 else
543 damage *= stacks;
545 break;
549 if(damage >= 0)
551 uint32 finalDamage;
552 if(m_originalCaster) // m_caster only passive source of cast
553 finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
554 else
555 finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
557 // post effects
558 switch(m_spellInfo->SpellFamilyName)
560 case SPELLFAMILY_WARRIOR:
562 // Bloodthirst
563 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
565 uint32 BTAura = 0;
566 switch(m_spellInfo->Id)
568 case 23881: BTAura = 23885; break;
569 case 23892: BTAura = 23886; break;
570 case 23893: BTAura = 23887; break;
571 case 23894: BTAura = 23888; break;
572 case 25251: BTAura = 25252; break;
573 case 30335: BTAura = 30339; break;
574 default:
575 sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
576 break;
579 if (BTAura)
580 m_caster->CastSpell(m_caster,BTAura,true);
582 break;
584 case SPELLFAMILY_PRIEST:
586 // Shadow Word: Death
587 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
588 // deals damage equal to damage done to caster if victim is not killed
589 m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
591 break;
593 case SPELLFAMILY_PALADIN:
595 // Judgement of Blood
596 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
598 int32 damagePoint = finalDamage * 33 / 100;
599 m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
601 break;
608 void Spell::EffectDummy(uint32 i)
610 if(!unitTarget && !gameObjTarget && !itemTarget)
611 return;
613 // selection by spell family
614 switch(m_spellInfo->SpellFamilyName)
616 case SPELLFAMILY_GENERIC:
617 // Gnomish Poultryizer trinket
618 switch(m_spellInfo->Id )
620 case 8063: // Deviate Fish
622 if(m_caster->GetTypeId() != TYPEID_PLAYER)
623 return;
625 uint32 spell_id = 0;
626 switch(urand(1,5))
628 case 1: spell_id = 8064; break; // Sleepy
629 case 2: spell_id = 8065; break; // Invigorate
630 case 3: spell_id = 8066; break; // Shrink
631 case 4: spell_id = 8067; break; // Party Time!
632 case 5: spell_id = 8068; break; // Healthy Spirit
634 m_caster->CastSpell(m_caster,spell_id,true,NULL);
635 return;
637 case 8213: // Savory Deviate Delight
639 if(m_caster->GetTypeId() != TYPEID_PLAYER)
640 return;
642 uint32 spell_id = 0;
643 switch(urand(1,2))
645 // Flip Out - ninja
646 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
647 // Yaaarrrr - pirate
648 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
650 m_caster->CastSpell(m_caster,spell_id,true,NULL);
651 return;
653 case 8593: // Symbol of life (restore creature to life)
654 case 31225: // Shimmering Vessel (restore creature to life)
656 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
657 return;
658 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
659 return;
661 case 12162: // Deep wounds
662 case 12850: // (now good common check for this spells)
663 case 12868:
665 if(!unitTarget)
666 return;
668 float damage;
669 // DW should benefit of attack power, damage percent mods etc.
670 // TODO: check if using offhand damage is correct and if it should be divided by 2
671 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
672 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
673 else
674 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
676 switch (m_spellInfo->Id)
678 case 12850: damage *= 0.2f; break;
679 case 12162: damage *= 0.4f; break;
680 case 12868: damage *= 0.6f; break;
681 default:
682 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
683 return;
686 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
687 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
688 return;
690 case 12975: //Last Stand
692 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
693 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
694 return;
696 case 13120: // net-o-matic
698 if(!unitTarget)
699 return;
701 uint32 spell_id = 0;
703 uint32 roll = urand(0, 99);
705 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
706 spell_id = 16566;
707 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
708 spell_id = 13119;
709 else // normal root
710 spell_id = 13099;
712 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
713 return;
715 case 13567: // Dummy Trigger
717 // can be used for different aura triggering, so select by aura
718 if(!m_triggeredByAuraSpell || !unitTarget)
719 return;
721 switch(m_triggeredByAuraSpell->Id)
723 case 26467: // Persistent Shield
724 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
725 break;
726 default:
727 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
728 break;
730 return;
732 case 14185: // Preparation Rogue
734 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
735 return;
737 //immediately finishes the cooldown on certain Rogue abilities
738 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
739 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
741 uint32 classspell = itr->first;
742 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
744 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
746 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
748 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
749 data << uint32(classspell);
750 data << uint64(m_caster->GetGUID());
751 ((Player*)m_caster)->GetSession()->SendPacket(&data);
754 return;
756 case 15998: // Capture Worg Pup
757 case 29435: // Capture Female Kaliri Hatchling
759 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
760 return;
762 Creature* creatureTarget = (Creature*)unitTarget;
763 creatureTarget->setDeathState(JUST_DIED);
764 creatureTarget->RemoveCorpse();
765 creatureTarget->SetHealth(0); // just for nice GM-mode view
766 return;
768 case 16589: // Noggenfogger Elixir
770 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
771 return;
773 uint32 spell_id = 0;
774 switch(urand(1,3))
776 case 1: spell_id = 16595; break;
777 case 2: spell_id = 16593; break;
778 default:spell_id = 16591; break;
781 m_caster->CastSpell(m_caster,spell_id,true,NULL);
782 return;
784 case 17251: // Spirit Healer Res
786 if(!unitTarget || !m_originalCaster)
787 return;
789 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
791 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
792 data << unitTarget->GetGUID();
793 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
795 return;
797 case 17271: // Test Fetid Skull
799 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
800 return;
802 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
804 m_caster->CastSpell(m_caster,spell_id,true,NULL);
805 return;
807 case 20577: // Cannibalize
808 if (unitTarget)
809 m_caster->CastSpell(m_caster,20578,false,NULL);
810 return;
811 case 23019: // Crystal Prison Dummy DND
813 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
814 return;
816 Creature* creatureTarget = (Creature*)unitTarget;
817 if(creatureTarget->isPet())
818 return;
820 creatureTarget->setDeathState(JUST_DIED);
821 creatureTarget->RemoveCorpse();
822 creatureTarget->SetHealth(0); // just for nice GM-mode view
824 GameObject* pGameObj = new GameObject;
826 Map *map = creatureTarget->GetMap();
828 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
829 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
830 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
832 delete pGameObj;
833 return;
836 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
837 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
838 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
839 pGameObj->SetSpellId(m_spellInfo->Id);
841 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
842 map->Add(pGameObj);
844 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
845 data << uint64(pGameObj->GetGUID());
846 m_caster->SendMessageToSet(&data,true);
848 return;
850 case 23074: // Arc. Dragonling
851 if (!m_CastItem) return;
852 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
853 return;
854 case 23075: // Mithril Mechanical Dragonling
855 if (!m_CastItem) return;
856 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
857 return;
858 case 23076: // Mechanical Dragonling
859 if (!m_CastItem) return;
860 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
861 return;
862 case 23133: // Gnomish Battle Chicken
863 if (!m_CastItem) return;
864 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
865 return;
866 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
868 int32 r = irand(0, 119);
869 if ( r < 20 ) // 1/6 polymorph
870 m_caster->CastSpell(m_caster,23444,true);
871 else if ( r < 100 ) // 4/6 evil twin
872 m_caster->CastSpell(m_caster,23445,true);
873 else // 1/6 miss the target
874 m_caster->CastSpell(m_caster,36902,true);
875 return;
877 case 23453: // Ultrasafe Transporter: Gadgetzan
878 if ( roll_chance_i(50) ) // success
879 m_caster->CastSpell(m_caster,23441,true);
880 else // failure
881 m_caster->CastSpell(m_caster,23446,true);
882 return;
883 case 23645: // Hourglass Sand
884 m_caster->RemoveAurasDueToSpell(23170);
885 return;
886 case 23725: // Gift of Life (warrior bwl trinket)
887 m_caster->CastSpell(m_caster,23782,true);
888 m_caster->CastSpell(m_caster,23783,true);
889 return;
890 case 25860: // Reindeer Transformation
892 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
893 return;
895 float flyspeed = m_caster->GetSpeedRate(MOVE_FLY);
896 float speed = m_caster->GetSpeedRate(MOVE_RUN);
898 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
900 //5 different spells used depending on mounted speed and if mount can fly or not
901 if (flyspeed >= 4.1f)
902 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
903 else if (flyspeed >= 3.8f)
904 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
905 else if (flyspeed >= 1.6f)
906 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
907 else if (speed >= 2.0f)
908 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
909 else
910 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
912 return;
914 //case 26074: // Holiday Cheer
915 // return; -- implemented at client side
916 case 28006: // Arcane Cloaking
918 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
919 m_caster->CastSpell(unitTarget,29294,true);
920 return;
922 case 28730: // Arcane Torrent (Mana)
924 int32 count = 0;
925 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
926 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
927 if ((*i)->GetId() == 28734)
928 ++count;
929 if (count)
931 m_caster->RemoveAurasDueToSpell(28734);
932 int32 bp = damage * count;
933 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
935 return;
937 case 29200: // Purify Helboar Meat
939 if( m_caster->GetTypeId() != TYPEID_PLAYER )
940 return;
942 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
944 m_caster->CastSpell(m_caster,spell_id,true,NULL);
945 return;
947 case 29858: // Soulshatter
948 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
949 m_caster->CastSpell(unitTarget,32835,true);
950 return;
951 case 30458: // Nigh Invulnerability
952 if (!m_CastItem) return;
953 if(roll_chance_i(86)) // success
954 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
955 else // backfire in 14% casts
956 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
957 return;
958 case 30507: // Poultryizer
959 if (!m_CastItem) return;
960 if(roll_chance_i(80)) // success
961 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
962 else // backfire 20%
963 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
964 return;
965 case 33060: // Make a Wish
967 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
968 return;
970 uint32 spell_id = 0;
972 switch(urand(1,5))
974 case 1: spell_id = 33053; break;
975 case 2: spell_id = 33057; break;
976 case 3: spell_id = 33059; break;
977 case 4: spell_id = 33062; break;
978 case 5: spell_id = 33064; break;
981 m_caster->CastSpell(m_caster,spell_id,true,NULL);
982 return;
984 case 35745:
986 uint32 spell_id;
987 switch(m_caster->GetAreaId())
989 case 3900: spell_id = 35743; break;
990 case 3742: spell_id = 35744; break;
991 default: return;
994 m_caster->CastSpell(m_caster,spell_id,true);
995 return;
997 case 37674: // Chaos Blast
998 if(unitTarget)
999 m_caster->CastSpell(unitTarget,37675,true);
1000 return;
1001 case 44875: // Complete Raptor Capture
1003 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1004 return;
1006 Creature* creatureTarget = (Creature*)unitTarget;
1008 creatureTarget->setDeathState(JUST_DIED);
1009 creatureTarget->RemoveCorpse();
1010 creatureTarget->SetHealth(0); // just for nice GM-mode view
1012 //cast spell Raptor Capture Credit
1013 m_caster->CastSpell(m_caster,42337,true,NULL);
1014 return;
1016 case 37573: //Temporal Phase Modulator
1018 if(!unitTarget)
1019 return;
1021 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1022 if(!tempSummon)
1023 return;
1025 uint32 health = tempSummon->GetHealth();
1026 const uint32 entry_list[6] = {21821, 21820, 21817};
1028 float x = tempSummon->GetPositionX();
1029 float y = tempSummon->GetPositionY();
1030 float z = tempSummon->GetPositionZ();
1031 float o = tempSummon->GetOrientation();
1033 tempSummon->UnSummon();
1035 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1036 if (!pCreature)
1037 return;
1039 pCreature->SetHealth(health);
1041 if(pCreature->AI())
1042 pCreature->AI()->AttackStart(m_caster);
1044 return;
1046 case 34665: //Administer Antidote
1048 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1049 return;
1051 if(!unitTarget)
1052 return;
1054 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1055 if(!tempSummon)
1056 return;
1058 uint32 health = tempSummon->GetHealth();
1060 float x = tempSummon->GetPositionX();
1061 float y = tempSummon->GetPositionY();
1062 float z = tempSummon->GetPositionZ();
1063 float o = tempSummon->GetOrientation();
1064 tempSummon->UnSummon();
1066 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1067 if (!pCreature)
1068 return;
1070 pCreature->SetHealth(health);
1071 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1073 if (pCreature->AI())
1074 pCreature->AI()->AttackStart(m_caster);
1076 return;
1078 case 44997: // Converting Sentry
1080 //Converted Sentry Credit
1081 m_caster->CastSpell(m_caster, 45009, true);
1082 return;
1084 case 45030: // Impale Emissary
1086 // Emissary of Hate Credit
1087 m_caster->CastSpell(m_caster, 45088, true);
1088 return;
1090 case 50243: // Teach Language
1092 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1093 return;
1095 // spell has a 1/3 chance to trigger one of the below
1096 if(roll_chance_i(66))
1097 return;
1098 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1100 // 1000001 - gnomish binary
1101 m_caster->CastSpell(m_caster, 50242, true);
1103 else
1105 // 01001000 - goblin binary
1106 m_caster->CastSpell(m_caster, 50246, true);
1109 return;
1111 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1113 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1114 return;
1116 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1117 bg->EventPlayerDroppedFlag((Player*)m_caster);
1119 m_caster->CastSpell(m_caster, 30452, true, NULL);
1120 return;
1124 //All IconID Check in there
1125 switch(m_spellInfo->SpellIconID)
1127 // Berserking (troll racial traits)
1128 case 1661:
1130 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1131 int32 melee_mod = 10;
1132 if (healthPerc <= 40)
1133 melee_mod = 30;
1134 if (healthPerc < 100 && healthPerc > 40)
1135 melee_mod = 10+(100-healthPerc)/3;
1137 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1138 int32 hasteModBasePoints1 = (5-melee_mod);
1139 int32 hasteModBasePoints2 = 5;
1141 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1142 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1143 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1144 return;
1147 break;
1148 case SPELLFAMILY_MAGE:
1149 switch(m_spellInfo->Id )
1151 case 11958: // Cold Snap
1153 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1154 return;
1156 // immediately finishes the cooldown on Frost spells
1157 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1158 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1160 if (itr->second->state == PLAYERSPELL_REMOVED)
1161 continue;
1163 uint32 classspell = itr->first;
1164 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1166 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1167 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1168 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1170 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1172 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1173 data << uint32(classspell);
1174 data << uint64(m_caster->GetGUID());
1175 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1178 return;
1180 case 32826:
1182 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1184 //Polymorph Cast Visual Rank 1
1185 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1186 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1188 return;
1191 break;
1192 case SPELLFAMILY_WARRIOR:
1193 // Charge
1194 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1196 int32 chargeBasePoints0 = damage;
1197 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1198 return;
1200 // Execute
1201 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1203 if(!unitTarget)
1204 return;
1206 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1207 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1208 m_caster->SetPower(POWER_RAGE,0);
1209 return;
1211 if(m_spellInfo->Id==21977) //Warrior's Wrath
1213 if(!unitTarget)
1214 return;
1216 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1217 return;
1219 break;
1220 case SPELLFAMILY_WARLOCK:
1221 //Life Tap (only it have this with dummy effect)
1222 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1224 float cost = m_currentBasePoints[0]+1;
1226 if(Player* modOwner = m_caster->GetSpellModOwner())
1227 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1229 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1231 if(int32(m_caster->GetHealth()) > dmg)
1233 // Shouldn't Appear in Combat Log
1234 m_caster->ModifyHealth(-dmg);
1236 int32 mana = dmg;
1238 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1239 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1241 // only Imp. Life Tap have this in combination with dummy aura
1242 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1243 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1246 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1248 // Mana Feed
1249 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1250 manaFeedVal = manaFeedVal * mana / 100;
1251 if(manaFeedVal > 0)
1252 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1254 else
1255 SendCastResult(SPELL_FAILED_FIZZLE);
1256 return;
1258 break;
1259 case SPELLFAMILY_PRIEST:
1260 switch(m_spellInfo->Id )
1262 case 28598: // Touch of Weakness triggered spell
1264 if(!unitTarget || !m_triggeredByAuraSpell)
1265 return;
1267 uint32 spellid = 0;
1268 switch(m_triggeredByAuraSpell->Id)
1270 case 2652: spellid = 2943; break; // Rank 1
1271 case 19261: spellid = 19249; break; // Rank 2
1272 case 19262: spellid = 19251; break; // Rank 3
1273 case 19264: spellid = 19252; break; // Rank 4
1274 case 19265: spellid = 19253; break; // Rank 5
1275 case 19266: spellid = 19254; break; // Rank 6
1276 case 25461: spellid = 25460; break; // Rank 7
1277 default:
1278 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1279 return;
1281 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1282 return;
1285 break;
1286 case SPELLFAMILY_DRUID:
1287 switch(m_spellInfo->Id )
1289 case 5420: // Tree of Life passive
1291 // Tree of Life area effect
1292 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1293 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1294 return;
1297 break;
1298 case SPELLFAMILY_ROGUE:
1299 switch(m_spellInfo->Id )
1301 case 31231: // Cheat Death
1303 m_caster->CastSpell(m_caster,45182,true);
1304 return;
1306 case 5938: // Shiv
1308 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1309 return;
1311 Player *pCaster = ((Player*)m_caster);
1313 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1314 if(!item)
1315 return;
1317 // all poison enchantments is temporary
1318 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1319 if(!enchant_id)
1320 return;
1322 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1323 if(!pEnchant)
1324 return;
1326 for (int s=0;s<3;s++)
1328 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1329 continue;
1331 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1332 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1333 continue;
1335 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1338 m_caster->CastSpell(unitTarget, 5940, true);
1339 return;
1342 break;
1343 case SPELLFAMILY_HUNTER:
1344 // Steady Shot
1345 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1347 if( !unitTarget || !unitTarget->isAlive())
1348 return;
1350 bool found = false;
1352 // check dazed affect
1353 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1354 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1356 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1358 found = true;
1359 break;
1363 if(found)
1364 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
1365 return;
1367 // Kill command
1368 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1370 if(m_caster->getClass()!=CLASS_HUNTER)
1371 return;
1373 // clear hunter crit aura state
1374 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1376 // additional damage from pet to pet target
1377 Pet* pet = m_caster->GetPet();
1378 if(!pet || !pet->getVictim())
1379 return;
1381 uint32 spell_id = 0;
1382 switch (m_spellInfo->Id)
1384 case 34026: spell_id = 34027; break; // rank 1
1385 default:
1386 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1387 return;
1390 pet->CastSpell(pet->getVictim(), spell_id, true);
1391 return;
1394 switch(m_spellInfo->Id)
1396 case 23989: //Readiness talent
1398 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1399 return;
1401 //immediately finishes the cooldown for hunter abilities
1402 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1403 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1405 uint32 classspell = itr->first;
1406 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1408 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1410 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1412 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1413 data << uint32(classspell);
1414 data << uint64(m_caster->GetGUID());
1415 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1418 return;
1420 case 37506: // Scatter Shot
1422 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1423 return;
1425 // break Auto Shot and autohit
1426 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1427 m_caster->AttackStop();
1428 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1429 return;
1432 break;
1433 case SPELLFAMILY_PALADIN:
1434 switch(m_spellInfo->SpellIconID)
1436 case 156: // Holy Shock
1438 if(!unitTarget)
1439 return;
1441 int hurt = 0;
1442 int heal = 0;
1444 switch(m_spellInfo->Id)
1446 case 20473: hurt = 25912; heal = 25914; break;
1447 case 20929: hurt = 25911; heal = 25913; break;
1448 case 20930: hurt = 25902; heal = 25903; break;
1449 case 27174: hurt = 27176; heal = 27175; break;
1450 case 33072: hurt = 33073; heal = 33074; break;
1451 default:
1452 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1453 return;
1456 if(m_caster->IsFriendlyTo(unitTarget))
1457 m_caster->CastSpell(unitTarget, heal, true, 0);
1458 else
1459 m_caster->CastSpell(unitTarget, hurt, true, 0);
1461 return;
1463 case 561: // Judgement of command
1465 if(!unitTarget)
1466 return;
1468 uint32 spell_id = m_currentBasePoints[i]+1;
1469 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1470 if(!spell_proto)
1471 return;
1473 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1475 // decreased damage (/2) for non-stunned target.
1476 SpellModifier *mod = new SpellModifier;
1477 mod->op = SPELLMOD_DAMAGE;
1478 mod->value = -50;
1479 mod->type = SPELLMOD_PCT;
1480 mod->spellId = m_spellInfo->Id;
1481 mod->effectId = i;
1482 mod->lastAffected = NULL;
1483 mod->mask = 0x0000020000000000LL;
1484 mod->charges = 0;
1486 ((Player*)m_caster)->AddSpellMod(mod, true);
1487 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1488 // mod deleted
1489 ((Player*)m_caster)->AddSpellMod(mod, false);
1491 else
1492 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1494 return;
1498 switch(m_spellInfo->Id)
1500 case 31789: // Righteous Defense (step 1)
1502 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1504 // non-standard cast requirement check
1505 if (!unitTarget || unitTarget->getAttackers().empty())
1507 // clear cooldown at fail
1508 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1510 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1512 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1513 data << uint32(m_spellInfo->Id);
1514 data << uint64(m_caster->GetGUID());
1515 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1518 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1519 return;
1522 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1523 // Clear targets for eff 1
1524 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1525 ihit->effectMask &= ~(1<<1);
1527 // not empty (checked)
1528 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1530 // chance to be selected from list
1531 float chance = 100.0f/attackers.size();
1532 uint32 count=0;
1533 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1535 if(!roll_chance_f(chance))
1536 continue;
1537 ++count;
1538 AddUnitTarget((*aItr), 1);
1541 // now let next effect cast spell at each target.
1542 return;
1544 case 37877: // Blessing of Faith
1546 if(!unitTarget)
1547 return;
1549 uint32 spell_id = 0;
1550 switch(unitTarget->getClass())
1552 case CLASS_DRUID: spell_id = 37878; break;
1553 case CLASS_PALADIN: spell_id = 37879; break;
1554 case CLASS_PRIEST: spell_id = 37880; break;
1555 case CLASS_SHAMAN: spell_id = 37881; break;
1556 default: return; // ignore for not healing classes
1559 m_caster->CastSpell(m_caster,spell_id,true);
1560 return;
1563 break;
1564 case SPELLFAMILY_SHAMAN:
1565 //Shaman Rockbiter Weapon
1566 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1568 uint32 spell_id = 0;
1569 switch(m_spellInfo->Id)
1571 case 8017: spell_id = 36494; break; // Rank 1
1572 case 8018: spell_id = 36750; break; // Rank 2
1573 case 8019: spell_id = 36755; break; // Rank 3
1574 case 10399: spell_id = 36759; break; // Rank 4
1575 case 16314: spell_id = 36763; break; // Rank 5
1576 case 16315: spell_id = 36766; break; // Rank 6
1577 case 16316: spell_id = 36771; break; // Rank 7
1578 case 25479: spell_id = 36775; break; // Rank 8
1579 case 25485: spell_id = 36499; break; // Rank 9
1580 default:
1581 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1582 return;
1585 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1587 if(!spellInfo)
1589 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1590 return;
1593 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1594 return;
1596 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1598 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1600 if(item->IsFitToSpellRequirements(m_spellInfo))
1602 Spell *spell = new Spell(m_caster, spellInfo, true);
1604 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1605 // at calculation applied affect from Elemental Weapons talent
1606 // real enchantment damage-1
1607 spell->m_currentBasePoints[1] = damage-1;
1609 SpellCastTargets targets;
1610 targets.setItemTarget( item );
1611 spell->prepare(&targets);
1615 return;
1618 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1620 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1621 return;
1623 // Regenerate 6% of Total Mana Every 3 secs
1624 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1625 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1626 return;
1629 break;
1632 // pet auras
1633 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1635 m_caster->AddPetAura(petSpell);
1636 return;
1640 void Spell::EffectTriggerSpellWithValue(uint32 i)
1642 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1644 // normal case
1645 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1647 if(!spellInfo)
1649 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1650 return;
1653 int32 bp = damage;
1654 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1657 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1659 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1660 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1662 if(!spellInfo)
1664 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1665 return;
1668 finish();
1669 Spell *spell = new Spell(m_caster, spellInfo, true);
1671 SpellCastTargets targets;
1672 targets.setUnitTarget( unitTarget);
1673 spell->prepare(&targets);
1675 m_caster->SetCurrentCastedSpell(spell);
1676 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1680 void Spell::EffectForceCast(uint32 i)
1682 if( !unitTarget )
1683 return;
1685 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1687 // normal case
1688 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1690 if(!spellInfo)
1692 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1693 return;
1696 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1699 void Spell::EffectTriggerSpell(uint32 i)
1701 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1703 // special cases
1704 switch(triggered_spell_id)
1706 // Vanish
1707 case 18461:
1709 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1710 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1711 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1713 // if this spell is given to NPC it must handle rest by it's own AI
1714 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1715 return;
1717 // get highest rank of the Stealth spell
1718 uint32 spellId = 0;
1719 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1720 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1722 // only highest rank is shown in spell book, so simply check if shown in spell book
1723 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1724 continue;
1726 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1727 if (!spellInfo)
1728 continue;
1730 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1732 spellId = spellInfo->Id;
1733 break;
1737 // no Stealth spell found
1738 if (!spellId)
1739 return;
1741 // reset cooldown on it if needed
1742 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1743 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1745 m_caster->CastSpell(m_caster, spellId, true);
1746 return;
1748 // just skip
1749 case 23770: // Sayge's Dark Fortune of *
1750 // not exist, common cooldown can be implemented in scripts if need.
1751 return;
1752 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1753 case 29284:
1755 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1756 if (!spell)
1757 return;
1759 for (int i=0; i < spell->StackAmount; ++i)
1760 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1761 return;
1763 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1764 case 29286:
1766 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1767 if (!spell)
1768 return;
1770 for (int i=0; i < spell->StackAmount; ++i)
1771 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1772 return;
1774 // Righteous Defense
1775 case 31980:
1777 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1778 return;
1780 // Cloak of Shadows
1781 case 35729 :
1783 Unit::AuraMap& Auras = m_caster->GetAuras();
1784 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1786 // remove all harmful spells on you...
1787 if( // ignore positive and passive auras
1788 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1789 // ignore physical auras
1790 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1791 // ignore immunity persistent spells
1792 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1794 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1795 iter = Auras.begin();
1798 return;
1800 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1801 case 41967:
1803 if (Unit *pet = m_caster->GetPet())
1804 pet->CastSpell(pet, 28305, true);
1805 return;
1809 // normal case
1810 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1812 if(!spellInfo)
1814 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1815 return;
1818 // some triggered spells require specific equipment
1819 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1821 // main hand weapon required
1822 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1824 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1826 // skip spell if no weapon in slot or broken
1827 if(!item || item->IsBroken() )
1828 return;
1830 // skip spell if weapon not fit to triggered spell
1831 if(!item->IsFitToSpellRequirements(spellInfo))
1832 return;
1835 // offhand hand weapon required
1836 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1838 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1840 // skip spell if no weapon in slot or broken
1841 if(!item || item->IsBroken() )
1842 return;
1844 // skip spell if weapon not fit to triggered spell
1845 if(!item->IsFitToSpellRequirements(spellInfo))
1846 return;
1850 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1851 bool instant = false;
1852 for(uint32 j = i+1; j < 3; ++j)
1854 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1856 instant = true;
1857 break;
1861 if(instant)
1863 if (unitTarget)
1864 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1866 else
1867 m_TriggerSpells.push_back(spellInfo);
1870 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1872 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1874 // normal case
1875 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1877 if(!spellInfo)
1879 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1880 m_spellInfo->Id,effect_idx,triggered_spell_id);
1881 return;
1884 if (m_CastItem)
1885 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1887 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1889 SpellCastTargets targets;
1890 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1891 spell->m_CastItem = m_CastItem;
1892 spell->prepare(&targets, NULL);
1895 void Spell::EffectTeleportUnits(uint32 i)
1897 if(!unitTarget || unitTarget->isInFlight())
1898 return;
1900 switch (m_spellInfo->EffectImplicitTargetB[i])
1902 case TARGET_INNKEEPER_COORDINATES:
1904 // Only players can teleport to innkeeper
1905 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1906 return;
1908 ((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);
1909 return;
1911 case TARGET_TABLE_X_Y_Z_COORDINATES:
1913 // TODO: Only players can teleport?
1914 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1915 return;
1916 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1917 if(!st)
1919 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1920 return;
1922 ((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);
1923 break;
1925 case TARGET_BEHIND_VICTIM:
1927 // Get selected target for player (or victim for units)
1928 Unit *pTarget = NULL;
1929 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1930 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1931 else
1932 pTarget = m_caster->getVictim();
1933 // No target present - return
1934 if (!pTarget)
1935 return;
1936 // Init dest coordinates
1937 uint32 mapid = m_caster->GetMapId();
1938 float x = m_targets.m_destX;
1939 float y = m_targets.m_destY;
1940 float z = m_targets.m_destZ;
1941 float orientation = pTarget->GetOrientation();
1942 // Teleport
1943 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1944 ((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));
1945 else
1947 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1948 WorldPacket data;
1949 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1950 unitTarget->SendMessageToSet(&data, false);
1952 return;
1954 default:
1956 // If not exist data for dest location - return
1957 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
1959 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
1960 return;
1962 // Init dest coordinates
1963 uint32 mapid = m_caster->GetMapId();
1964 float x = m_targets.m_destX;
1965 float y = m_targets.m_destY;
1966 float z = m_targets.m_destZ;
1967 float orientation = unitTarget->GetOrientation();
1968 // Teleport
1969 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1970 ((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));
1971 else
1973 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1974 WorldPacket data;
1975 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1976 unitTarget->SendMessageToSet(&data, false);
1978 return;
1982 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1983 switch ( m_spellInfo->Id )
1985 // Dimensional Ripper - Everlook
1986 case 23442:
1988 int32 r = irand(0, 119);
1989 if ( r >= 70 ) // 7/12 success
1991 if ( r < 100 ) // 4/12 evil twin
1992 m_caster->CastSpell(m_caster,23445,true);
1993 else // 1/12 fire
1994 m_caster->CastSpell(m_caster,23449,true);
1996 return;
1998 // Ultrasafe Transporter: Toshley's Station
1999 case 36941:
2001 if ( roll_chance_i(50) ) // 50% success
2003 int32 rand_eff = urand(1,7);
2004 switch ( rand_eff )
2006 case 1:
2007 // soul split - evil
2008 m_caster->CastSpell(m_caster,36900,true);
2009 break;
2010 case 2:
2011 // soul split - good
2012 m_caster->CastSpell(m_caster,36901,true);
2013 break;
2014 case 3:
2015 // Increase the size
2016 m_caster->CastSpell(m_caster,36895,true);
2017 break;
2018 case 4:
2019 // Decrease the size
2020 m_caster->CastSpell(m_caster,36893,true);
2021 break;
2022 case 5:
2023 // Transform
2025 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2026 m_caster->CastSpell(m_caster,36897,true);
2027 else
2028 m_caster->CastSpell(m_caster,36899,true);
2029 break;
2031 case 6:
2032 // chicken
2033 m_caster->CastSpell(m_caster,36940,true);
2034 break;
2035 case 7:
2036 // evil twin
2037 m_caster->CastSpell(m_caster,23445,true);
2038 break;
2041 return;
2043 // Dimensional Ripper - Area 52
2044 case 36890:
2046 if ( roll_chance_i(50) ) // 50% success
2048 int32 rand_eff = urand(1,4);
2049 switch ( rand_eff )
2051 case 1:
2052 // soul split - evil
2053 m_caster->CastSpell(m_caster,36900,true);
2054 break;
2055 case 2:
2056 // soul split - good
2057 m_caster->CastSpell(m_caster,36901,true);
2058 break;
2059 case 3:
2060 // Increase the size
2061 m_caster->CastSpell(m_caster,36895,true);
2062 break;
2063 case 4:
2064 // Transform
2066 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2067 m_caster->CastSpell(m_caster,36897,true);
2068 else
2069 m_caster->CastSpell(m_caster,36899,true);
2070 break;
2074 return;
2079 void Spell::EffectApplyAura(uint32 i)
2081 if(!unitTarget)
2082 return;
2084 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2085 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2086 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2087 return;
2089 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2090 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2091 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2092 return;
2094 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2095 if(!caster)
2096 return;
2098 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2100 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2102 // Now Reduce spell duration using data received at spell hit
2103 int32 duration = Aur->GetAuraMaxDuration();
2104 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2105 Aur->setDiminishGroup(m_diminishGroup);
2107 // if Aura removed and deleted, do not continue.
2108 if(duration== 0 && !(Aur->IsPermanent()))
2110 delete Aur;
2111 return;
2114 if(duration != Aur->GetAuraMaxDuration())
2116 Aur->SetAuraMaxDuration(duration);
2117 Aur->SetAuraDuration(duration);
2120 bool added = unitTarget->AddAura(Aur);
2122 // Aura not added and deleted in AddAura call;
2123 if (!added)
2124 return;
2126 // found crash at character loading, broken pointer to Aur...
2127 // Aur was deleted in AddAura()...
2128 if(!Aur)
2129 return;
2131 // TODO Make a way so it works for every related spell!
2132 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2134 uint32 spellId = 0;
2135 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2136 spellId = 6788; // Weakened Soul
2137 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2138 spellId = 25771; // Forbearance
2139 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2140 spellId = 41425; // Hypothermia
2141 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2142 spellId = 11196; // Recently Bandaged
2143 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2144 spellId = 23230; // Blood Fury - Healing Reduction
2146 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2147 if (AdditionalSpellInfo)
2149 // applied at target by target
2150 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2151 unitTarget->AddAura(AdditionalAura);
2152 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2156 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2157 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2158 m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
2161 void Spell::EffectUnlearnSpecialization( uint32 i )
2163 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2164 return;
2166 Player *_player = (Player*)unitTarget;
2167 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2169 _player->removeSpell(spellToUnlearn);
2171 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2174 void Spell::EffectPowerDrain(uint32 i)
2176 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2177 return;
2179 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2181 if(!unitTarget)
2182 return;
2183 if(!unitTarget->isAlive())
2184 return;
2185 if(unitTarget->getPowerType() != drain_power)
2186 return;
2187 if(damage < 0)
2188 return;
2190 uint32 curPower = unitTarget->GetPower(drain_power);
2192 //add spell damage bonus
2193 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2195 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2196 uint32 power = damage;
2197 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2198 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2200 int32 new_damage;
2201 if(curPower < power)
2202 new_damage = curPower;
2203 else
2204 new_damage = power;
2206 unitTarget->ModifyPower(drain_power,-new_damage);
2208 if(drain_power == POWER_MANA)
2210 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2211 if(manaMultiplier==0)
2212 manaMultiplier = 1;
2214 if(Player *modOwner = m_caster->GetSpellModOwner())
2215 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2217 int32 gain = int32(new_damage*manaMultiplier);
2219 m_caster->ModifyPower(POWER_MANA,gain);
2220 //send log
2221 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2225 void Spell::EffectSendEvent(uint32 EffectIndex)
2227 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2229 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2230 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2232 switch(m_spellInfo->Id)
2234 case 23333: // Pickup Horde Flag
2235 /*do not uncomment .
2236 if(bg->GetTypeID()==BATTLEGROUND_WS)
2237 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2238 sLog.outDebug("Send Event Horde Flag Picked Up");
2239 break;
2240 /* not used :
2241 case 23334: // Drop Horde Flag
2242 if(bg->GetTypeID()==BATTLEGROUND_WS)
2243 bg->EventPlayerDroppedFlag((Player*)m_caster);
2244 sLog.outDebug("Drop Horde Flag");
2245 break;
2247 case 23335: // Pickup Alliance Flag
2248 /*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
2249 if(bg->GetTypeID()==BATTLEGROUND_WS)
2250 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2251 sLog.outDebug("Send Event Alliance Flag Picked Up");
2252 break;
2253 /* not used :
2254 case 23336: // Drop Alliance Flag
2255 if(bg->GetTypeID()==BATTLEGROUND_WS)
2256 bg->EventPlayerDroppedFlag((Player*)m_caster);
2257 sLog.outDebug("Drop Alliance Flag");
2258 break;
2259 case 23385: // Alliance Flag Returns
2260 if(bg->GetTypeID()==BATTLEGROUND_WS)
2261 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2262 sLog.outDebug("Alliance Flag Returned");
2263 break;
2264 case 23386: // Horde Flag Returns
2265 if(bg->GetTypeID()==BATTLEGROUND_WS)
2266 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2267 sLog.outDebug("Horde Flag Returned");
2268 break;*/
2269 case 34976:
2271 if(bg->GetTypeID()==BATTLEGROUND_EY)
2272 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2274 break;
2275 default:
2276 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2277 break;
2281 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2282 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2285 void Spell::EffectPowerBurn(uint32 i)
2287 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2288 return;
2290 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2292 if(!unitTarget)
2293 return;
2294 if(!unitTarget->isAlive())
2295 return;
2296 if(unitTarget->getPowerType()!=powertype)
2297 return;
2298 if(damage < 0)
2299 return;
2301 int32 curPower = int32(unitTarget->GetPower(powertype));
2303 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2304 uint32 power = damage;
2305 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2306 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2308 int32 new_damage = (curPower < power) ? curPower : power;
2310 unitTarget->ModifyPower(powertype,-new_damage);
2311 float multiplier = m_spellInfo->EffectMultipleValue[i];
2313 if(Player *modOwner = m_caster->GetSpellModOwner())
2314 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2316 new_damage = int32(new_damage*multiplier);
2317 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2320 void Spell::EffectHeal( uint32 /*i*/ )
2322 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2324 // Try to get original caster
2325 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2327 // Skip if m_originalCaster not available
2328 if (!caster)
2329 return;
2331 int32 addhealth = damage;
2333 // Vessel of the Naaru (Vial of the Sunwell trinket)
2334 if (m_spellInfo->Id == 45064)
2336 // Amount of heal - depends from stacked Holy Energy
2337 int damageAmount = 0;
2338 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2339 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2340 if((*i)->GetId() == 45062)
2341 damageAmount+=(*i)->GetModifier()->m_amount;
2342 if (damageAmount)
2343 m_caster->RemoveAurasDueToSpell(45062);
2345 addhealth += damageAmount;
2347 // Swiftmend - consumes Regrowth or Rejuvenation
2348 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2350 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2351 // find most short by duration
2352 Aura *targetAura = NULL;
2353 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2355 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2356 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2358 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2359 targetAura = *i;
2363 if(!targetAura)
2365 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2366 return;
2368 int idx = 0;
2369 while(idx < 3)
2371 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2372 break;
2373 idx++;
2376 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2377 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2378 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2380 addhealth += tickheal * tickcount;
2382 else
2383 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2385 bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
2386 if (crit)
2387 addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
2388 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
2390 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2391 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2393 if(caster->GetTypeId()==TYPEID_PLAYER)
2394 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2395 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2397 // ignore item heals
2398 if(m_CastItem)
2399 return;
2401 uint32 procHealer = PROC_FLAG_HEAL;
2402 if (crit)
2403 procHealer |= PROC_FLAG_CRIT_HEAL;
2405 m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
2409 void Spell::EffectHealPct( uint32 /*i*/ )
2411 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2413 // Try to get original caster
2414 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2416 // Skip if m_originalCaster not available
2417 if (!caster)
2418 return;
2420 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2421 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2423 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2424 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2426 if(caster->GetTypeId()==TYPEID_PLAYER)
2427 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2428 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2432 void Spell::EffectHealMechanical( uint32 /*i*/ )
2434 // Mechanic creature type should be correctly checked by targetCreatureType field
2435 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2437 // Try to get original caster
2438 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2440 // Skip if m_originalCaster not available
2441 if (!caster)
2442 return;
2444 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2445 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2446 unitTarget->ModifyHealth( int32(damage) );
2450 void Spell::EffectHealthLeech(uint32 i)
2452 if(!unitTarget)
2453 return;
2454 if(!unitTarget->isAlive())
2455 return;
2457 if(damage < 0)
2458 return;
2460 sLog.outDebug("HealthLeech :%i", damage);
2462 float multiplier = m_spellInfo->EffectMultipleValue[i];
2464 if(Player *modOwner = m_caster->GetSpellModOwner())
2465 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2467 int32 new_damage = int32(damage*multiplier);
2468 uint32 curHealth = unitTarget->GetHealth();
2469 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2470 if(curHealth < new_damage)
2471 new_damage = curHealth;
2473 if(m_caster->isAlive())
2475 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2477 m_caster->ModifyHealth(new_damage);
2479 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2480 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2484 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2486 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2487 return;
2489 Player* player = (Player*)unitTarget;
2491 uint32 newitemid = itemtype;
2492 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2493 if(!pProto)
2495 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2496 return;
2499 uint32 num_to_add;
2501 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2502 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2504 int32 basePoints = m_currentBasePoints[i];
2505 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2506 if (randomPoints)
2507 num_to_add = basePoints + irand(1, randomPoints);
2508 else
2509 num_to_add = basePoints + 1;
2511 else if (pProto->MaxCount == 1)
2512 num_to_add = 1;
2513 else if(player->getLevel() >= m_spellInfo->spellLevel)
2515 int32 basePoints = m_currentBasePoints[i];
2516 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2517 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2519 else
2520 num_to_add = 2;
2522 if (num_to_add < 1)
2523 num_to_add = 1;
2524 if (num_to_add > pProto->Stackable)
2525 num_to_add = pProto->Stackable;
2527 // init items_count to 1, since 1 item will be created regardless of specialization
2528 int items_count=1;
2529 // the chance to create additional items
2530 float additionalCreateChance=0.0f;
2531 // the maximum number of created additional items
2532 uint8 additionalMaxNum=0;
2533 // get the chance and maximum number for creating extra items
2534 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2536 // roll with this chance till we roll not to create or we create the max num
2537 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2538 ++items_count;
2541 // really will be created more items
2542 num_to_add *= items_count;
2544 // can the player store the new item?
2545 ItemPosCountVec dest;
2546 uint32 no_space = 0;
2547 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2548 if( msg != EQUIP_ERR_OK )
2550 // convert to possible store amount
2551 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2552 num_to_add -= no_space;
2553 else
2555 // if not created by another reason from full inventory or unique items amount limitation
2556 player->SendEquipError( msg, NULL, NULL );
2557 return;
2561 if(num_to_add)
2563 // create the new item and store it
2564 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2566 // was it successful? return error if not
2567 if(!pItem)
2569 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2570 return;
2573 // set the "Crafted by ..." property of the item
2574 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2575 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2577 // send info to the client
2578 if(pItem)
2579 player->SendNewItem(pItem, num_to_add, true, true);
2581 // we succeeded in creating at least one item, so a levelup is possible
2582 player->UpdateCraftSkill(m_spellInfo->Id);
2585 // for battleground marks send by mail if not add all expected
2586 if(no_space > 0 )
2588 BattleGroundTypeId bgType;
2589 switch(m_spellInfo->Id)
2591 case SPELL_AV_MARK_WINNER:
2592 case SPELL_AV_MARK_LOSER:
2593 bgType = BATTLEGROUND_AV;
2594 break;
2595 case SPELL_WS_MARK_WINNER:
2596 case SPELL_WS_MARK_LOSER:
2597 bgType = BATTLEGROUND_WS;
2598 break;
2599 case SPELL_AB_MARK_WINNER:
2600 case SPELL_AB_MARK_LOSER:
2601 bgType = BATTLEGROUND_AB;
2602 break;
2603 default:
2604 return;
2607 if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
2608 bg->SendRewardMarkByMail(player,newitemid,no_space);
2612 void Spell::EffectCreateItem(uint32 i)
2614 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2617 void Spell::EffectPersistentAA(uint32 i)
2619 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2621 if(Player* modOwner = m_caster->GetSpellModOwner())
2622 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2624 int32 duration = GetSpellDuration(m_spellInfo);
2625 DynamicObject* dynObj = new DynamicObject;
2626 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))
2628 delete dynObj;
2629 return;
2631 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2632 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2633 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2634 m_caster->AddDynObject(dynObj);
2635 dynObj->GetMap()->Add(dynObj);
2638 void Spell::EffectEnergize(uint32 i)
2640 if(!unitTarget)
2641 return;
2642 if(!unitTarget->isAlive())
2643 return;
2645 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2646 return;
2648 // Some level depends spells
2649 int multiplier = 0;
2650 int level_diff = 0;
2651 switch (m_spellInfo->Id)
2653 // Restore Energy
2654 case 9512:
2655 level_diff = m_caster->getLevel() - 40;
2656 multiplier = 2;
2657 break;
2658 // Blood Fury
2659 case 24571:
2660 level_diff = m_caster->getLevel() - 60;
2661 multiplier = 10;
2662 break;
2663 // Burst of Energy
2664 case 24532:
2665 level_diff = m_caster->getLevel() - 60;
2666 multiplier = 4;
2667 break;
2668 default:
2669 break;
2672 if (level_diff > 0)
2673 damage -= multiplier * level_diff;
2675 if(damage < 0)
2676 return;
2678 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2680 if(unitTarget->GetMaxPower(power) == 0)
2681 return;
2683 unitTarget->ModifyPower(power,damage);
2684 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2686 // Mad Alchemist's Potion
2687 if (m_spellInfo->Id == 45051)
2689 // find elixirs on target
2690 uint32 elixir_mask = 0;
2691 Unit::AuraMap& Auras = unitTarget->GetAuras();
2692 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2694 uint32 spell_id = itr->second->GetId();
2695 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2696 elixir_mask |= mask;
2699 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2700 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2702 // get all available elixirs by mask and spell level
2703 std::vector<uint32> elixirs;
2704 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2705 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2707 if (itr->second & elixir_mask)
2709 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2710 continue;
2712 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2713 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2714 continue;
2716 elixirs.push_back(itr->first);
2720 if (!elixirs.empty())
2722 // cast random elixir on target
2723 uint32 rand_spell = urand(0,elixirs.size()-1);
2724 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2729 void Spell::EffectEnergisePct(uint32 i)
2731 if(!unitTarget)
2732 return;
2733 if(!unitTarget->isAlive())
2734 return;
2736 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2737 return;
2739 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2741 uint32 maxPower = unitTarget->GetMaxPower(power);
2742 if(maxPower == 0)
2743 return;
2745 uint32 gain = damage * maxPower / 100;
2746 unitTarget->ModifyPower(power, gain);
2747 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2750 void Spell::SendLoot(uint64 guid, LootType loottype)
2752 Player* player = (Player*)m_caster;
2753 if (!player)
2754 return;
2756 if (gameObjTarget)
2758 switch (gameObjTarget->GetGoType())
2760 case GAMEOBJECT_TYPE_DOOR:
2761 case GAMEOBJECT_TYPE_BUTTON:
2762 gameObjTarget->UseDoorOrButton();
2763 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2764 return;
2766 case GAMEOBJECT_TYPE_QUESTGIVER:
2767 // start or end quest
2768 player->PrepareQuestMenu(guid);
2769 player->SendPreparedQuest(guid);
2770 return;
2772 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2773 // triggering linked GO
2774 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2775 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2776 return;
2778 case GAMEOBJECT_TYPE_GOOBER:
2779 // goober_scripts can be triggered if the player don't have the quest
2780 if (gameObjTarget->GetGOInfo()->goober.eventId)
2782 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2783 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2786 // cast goober spell
2787 if (gameObjTarget->GetGOInfo()->goober.questId)
2788 ///Quest require to be active for GO using
2789 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2790 return;
2792 gameObjTarget->AddUniqueUse(player);
2793 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2795 //TODO? Objective counting called without spell check but with quest objective check
2796 // if send spell id then this line will duplicate to spell casting call (double counting)
2797 // So we or have this line and not required in quest_template have reqSpellIdN
2798 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2799 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2801 // triggering linked GO
2802 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2803 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2805 return;
2807 case GAMEOBJECT_TYPE_CHEST:
2808 // TODO: possible must be moved to loot release (in different from linked triggering)
2809 if (gameObjTarget->GetGOInfo()->chest.eventId)
2811 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2812 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2815 // triggering linked GO
2816 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2817 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2819 // Don't return, let loots been taken
2823 // Send loot
2824 player->SendLoot(guid, loottype);
2827 void Spell::EffectOpenLock(uint32 /*i*/)
2829 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2831 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2832 return;
2835 Player* player = (Player*)m_caster;
2837 LootType loottype = LOOT_CORPSE;
2838 uint32 lockId = 0;
2839 uint64 guid = 0;
2841 // Get lockId
2842 if(gameObjTarget)
2844 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2845 // Arathi Basin banner opening !
2846 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2847 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2849 //isAllowUseBattleGroundObject() already called in CanCast()
2850 // in battleground check
2851 if(BattleGround *bg = player->GetBattleGround())
2853 // check if it's correct bg
2854 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2855 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2856 return;
2859 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2861 //isAllowUseBattleGroundObject() already called in CanCast()
2862 // in battleground check
2863 if(BattleGround *bg = player->GetBattleGround())
2865 if(bg->GetTypeID() == BATTLEGROUND_EY)
2866 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2867 return;
2870 lockId = gameObjTarget->GetLockId();
2871 guid = gameObjTarget->GetGUID();
2873 else if(itemTarget)
2875 lockId = itemTarget->GetProto()->LockID;
2876 guid = itemTarget->GetGUID();
2878 else
2880 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2881 return;
2884 if(!lockId) // possible case for GO and maybe for items.
2886 SendLoot(guid, loottype);
2887 return;
2890 // Get LockInfo
2891 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2893 if (!lockInfo)
2895 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2896 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2897 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2898 return;
2901 // check key
2902 for(int i = 0; i < 8; ++i)
2904 // Type==1 This means lockInfo->Index[i] is an item
2905 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2907 SendLoot(guid, loottype);
2908 return;
2912 uint32 SkillId = 0;
2913 // Check and skill-up skill
2914 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2915 SkillId = m_spellInfo->EffectMiscValue[1];
2916 // pickpocketing spells
2917 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2918 SkillId = SKILL_LOCKPICKING;
2920 // skill bonus provided by casting spell (mostly item spells)
2921 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2923 uint32 reqSkillValue = lockInfo->Skill[0];
2925 if(lockInfo->Skill[1]) // required pick lock skill applying
2927 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2929 SendCastResult(SPELL_FAILED_FIZZLE);
2930 return;
2933 reqSkillValue = lockInfo->Skill[1];
2935 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2937 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2938 return;
2941 if ( SkillId )
2943 loottype = LOOT_SKINNING;
2944 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2946 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2947 return;
2950 // update skill if really known
2951 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2952 if(SkillValue) // non only item base skill
2954 if(gameObjTarget)
2956 // Allow one skill-up until respawned
2957 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
2958 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
2959 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
2961 else if(itemTarget)
2963 // Do one skill-up
2964 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2965 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
2970 SendLoot(guid, loottype);
2973 void Spell::EffectSummonChangeItem(uint32 i)
2975 if(m_caster->GetTypeId() != TYPEID_PLAYER)
2976 return;
2978 Player *player = (Player*)m_caster;
2980 // applied only to using item
2981 if(!m_CastItem)
2982 return;
2984 // ... only to item in own inventory/bank/equip_slot
2985 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
2986 return;
2988 uint32 newitemid = m_spellInfo->EffectItemType[i];
2989 if(!newitemid)
2990 return;
2992 uint16 pos = m_CastItem->GetPos();
2994 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
2995 if( !pNewItem )
2996 return;
2998 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3000 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3001 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3004 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3006 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3007 player->DurabilityLoss(pNewItem, loosePercent);
3010 if( player->IsInventoryPos( pos ) )
3012 ItemPosCountVec dest;
3013 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3014 if( msg == EQUIP_ERR_OK )
3016 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3018 // prevent crash at access and unexpected charges counting with item update queue corrupt
3019 if(m_CastItem==m_targets.getItemTarget())
3020 m_targets.setItemTarget(NULL);
3022 m_CastItem = NULL;
3024 player->StoreItem( dest, pNewItem, true);
3025 return;
3028 else if( player->IsBankPos ( pos ) )
3030 ItemPosCountVec dest;
3031 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3032 if( msg == EQUIP_ERR_OK )
3034 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3036 // prevent crash at access and unexpected charges counting with item update queue corrupt
3037 if(m_CastItem==m_targets.getItemTarget())
3038 m_targets.setItemTarget(NULL);
3040 m_CastItem = NULL;
3042 player->BankItem( dest, pNewItem, true);
3043 return;
3046 else if( player->IsEquipmentPos ( pos ) )
3048 uint16 dest;
3049 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3050 if( msg == EQUIP_ERR_OK )
3052 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3054 // prevent crash at access and unexpected charges counting with item update queue corrupt
3055 if(m_CastItem==m_targets.getItemTarget())
3056 m_targets.setItemTarget(NULL);
3058 m_CastItem = NULL;
3060 player->EquipItem( dest, pNewItem, true);
3061 player->AutoUnequipOffhandIfNeed();
3062 return;
3066 // fail
3067 delete pNewItem;
3070 void Spell::EffectOpenSecretSafe(uint32 i)
3072 EffectOpenLock(i); //no difference for now
3075 void Spell::EffectProficiency(uint32 /*i*/)
3077 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3078 return;
3079 Player *p_target = (Player*)unitTarget;
3081 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3082 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3084 p_target->AddWeaponProficiency(subClassMask);
3085 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3087 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3089 p_target->AddArmorProficiency(subClassMask);
3090 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3094 void Spell::EffectApplyAreaAura(uint32 i)
3096 if(!unitTarget)
3097 return;
3098 if(!unitTarget->isAlive())
3099 return;
3101 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3102 unitTarget->AddAura(Aur);
3105 void Spell::EffectSummonType(uint32 i)
3107 switch(m_spellInfo->EffectMiscValueB[i])
3109 case SUMMON_TYPE_GUARDIAN:
3110 case SUMMON_TYPE_POSESSED:
3111 case SUMMON_TYPE_POSESSED2:
3112 EffectSummonGuardian(i);
3113 break;
3114 case SUMMON_TYPE_WILD:
3115 EffectSummonWild(i);
3116 break;
3117 case SUMMON_TYPE_DEMON:
3118 EffectSummonDemon(i);
3119 break;
3120 case SUMMON_TYPE_SUMMON:
3121 EffectSummon(i);
3122 break;
3123 case SUMMON_TYPE_CRITTER:
3124 case SUMMON_TYPE_CRITTER2:
3125 case SUMMON_TYPE_CRITTER3:
3126 EffectSummonCritter(i);
3127 break;
3128 case SUMMON_TYPE_TOTEM_SLOT1:
3129 case SUMMON_TYPE_TOTEM_SLOT2:
3130 case SUMMON_TYPE_TOTEM_SLOT3:
3131 case SUMMON_TYPE_TOTEM_SLOT4:
3132 case SUMMON_TYPE_TOTEM:
3133 EffectSummonTotem(i);
3134 break;
3135 case SUMMON_TYPE_UNKNOWN1:
3136 case SUMMON_TYPE_UNKNOWN2:
3137 case SUMMON_TYPE_UNKNOWN3:
3138 case SUMMON_TYPE_UNKNOWN4:
3139 case SUMMON_TYPE_UNKNOWN5:
3140 break;
3141 default:
3142 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3143 break;
3147 void Spell::EffectSummon(uint32 i)
3149 if(m_caster->GetPetGUID())
3150 return;
3152 if(!unitTarget)
3153 return;
3154 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3155 if(!pet_entry)
3156 return;
3157 uint32 level = m_caster->getLevel();
3158 Pet* spawnCreature = new Pet(SUMMON_PET);
3160 if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
3162 // set timer for unsummon
3163 int32 duration = GetSpellDuration(m_spellInfo);
3164 if(duration > 0)
3165 spawnCreature->SetDuration(duration);
3167 return;
3170 Map *map = m_caster->GetMap();
3171 uint32 pet_number = objmgr.GeneratePetNumber();
3172 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3174 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3175 delete spawnCreature;
3176 return;
3179 // Summon in dest location
3180 float x,y,z;
3181 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3183 x = m_targets.m_destX;
3184 y = m_targets.m_destY;
3185 z = m_targets.m_destZ;
3187 else
3188 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3190 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3192 if(!spawnCreature->IsPositionValid())
3194 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3195 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3196 delete spawnCreature;
3197 return;
3200 // set timer for unsummon
3201 int32 duration = GetSpellDuration(m_spellInfo);
3202 if(duration > 0)
3203 spawnCreature->SetDuration(duration);
3205 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3206 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3207 spawnCreature->setPowerType(POWER_MANA);
3208 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3209 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3210 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3211 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3212 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3213 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3214 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3215 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3216 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3218 spawnCreature->InitStatsForLevel(level);
3220 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3222 spawnCreature->AIM_Initialize();
3223 spawnCreature->InitPetCreateSpells();
3224 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3225 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3227 std::string name = m_caster->GetName();
3228 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3229 spawnCreature->SetName( name );
3231 map->Add((Creature*)spawnCreature);
3233 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3235 m_caster->SetPet(spawnCreature);
3236 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3237 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3238 ((Player*)m_caster)->PetSpellInitialize();
3242 void Spell::EffectLearnSpell(uint32 i)
3244 if(!unitTarget)
3245 return;
3247 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3249 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3250 EffectLearnPetSpell(i);
3252 return;
3255 Player *player = (Player*)unitTarget;
3257 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3258 player->learnSpell(spellToLearn);
3260 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3263 void Spell::EffectDispel(uint32 i)
3265 if(!unitTarget)
3266 return;
3268 // Fill possible dispell list
3269 std::vector <Aura *> dispel_list;
3271 // Create dispel mask by dispel type
3272 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3273 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3274 Unit::AuraMap const& auras = unitTarget->GetAuras();
3275 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3277 Aura *aur = (*itr).second;
3278 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3280 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3282 bool positive = true;
3283 if (!aur->IsPositive())
3284 positive = false;
3285 else
3286 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3288 // do not remove positive auras if friendly target
3289 // negative auras if non-friendly target
3290 if(positive == unitTarget->IsFriendlyTo(m_caster))
3291 continue;
3293 // Add aura to dispel list
3294 dispel_list.push_back(aur);
3297 // Ok if exist some buffs for dispel try dispel it
3298 if (!dispel_list.empty())
3300 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3301 std::list < uint32 > fail_list; // spell_id
3302 int32 list_size = dispel_list.size();
3303 // Dispell N = damage buffs (or while exist buffs for dispel)
3304 for (int32 count=0; count < damage && list_size > 0; ++count)
3306 // Random select buff for dispel
3307 Aura *aur = dispel_list[urand(0, list_size-1)];
3309 SpellEntry const* spellInfo = aur->GetSpellProto();
3310 // Base dispel chance
3311 // TODO: possible chance depend from spell level??
3312 int32 miss_chance = 0;
3313 // Apply dispel mod from aura caster
3314 if (Unit *caster = aur->GetCaster())
3316 if ( Player* modOwner = caster->GetSpellModOwner() )
3317 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3319 // Try dispel
3320 if (roll_chance_i(miss_chance))
3321 fail_list.push_back(aur->GetId());
3322 else
3323 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3324 // Remove buff from list for prevent doubles
3325 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3327 Aura *dispeled = *j;
3328 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3330 j = dispel_list.erase(j);
3331 --list_size;
3333 else
3334 ++j;
3337 // Send success log and really remove auras
3338 if (!success_list.empty())
3340 int32 count = success_list.size();
3341 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3342 data.append(unitTarget->GetPackGUID()); // Victim GUID
3343 data.append(m_caster->GetPackGUID()); // Caster GUID
3344 data << uint32(m_spellInfo->Id); // Dispell spell id
3345 data << uint8(0); // not used
3346 data << uint32(count); // count
3347 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3349 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3350 data << uint32(spellInfo->Id); // Spell Id
3351 data << uint8(0); // 0 - dispeled !=0 cleansed
3352 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3354 m_caster->SendMessageToSet(&data, true);
3356 // On succes dispel
3357 // Devour Magic
3358 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3360 uint32 heal_spell = 0;
3361 switch (m_spellInfo->Id)
3363 case 19505: heal_spell = 19658; break;
3364 case 19731: heal_spell = 19732; break;
3365 case 19734: heal_spell = 19733; break;
3366 case 19736: heal_spell = 19735; break;
3367 case 27276: heal_spell = 27278; break;
3368 case 27277: heal_spell = 27279; break;
3369 default:
3370 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3371 break;
3373 if (heal_spell)
3374 m_caster->CastSpell(m_caster, heal_spell, true);
3377 // Send fail log to client
3378 if (!fail_list.empty())
3380 // Failed to dispell
3381 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3382 data << uint64(m_caster->GetGUID()); // Caster GUID
3383 data << uint64(unitTarget->GetGUID()); // Victim GUID
3384 data << uint32(m_spellInfo->Id); // Dispell spell id
3385 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3386 data << uint32(*j); // Spell Id
3387 m_caster->SendMessageToSet(&data, true);
3392 void Spell::EffectDualWield(uint32 /*i*/)
3394 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
3395 ((Player*)unitTarget)->SetCanDualWield(true);
3398 void Spell::EffectPull(uint32 /*i*/)
3400 // TODO: create a proper pull towards distract spell center for distract
3401 sLog.outDebug("WORLD: Spell Effect DUMMY");
3404 void Spell::EffectDistract(uint32 /*i*/)
3406 // Check for possible target
3407 if (!unitTarget || unitTarget->isInCombat())
3408 return;
3410 // target must be OK to do this
3411 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3412 return;
3414 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3416 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3418 // For players just turn them
3419 WorldPacket data;
3420 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3421 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3422 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3424 else
3426 // Set creature Distracted, Stop it, And turn it
3427 unitTarget->SetOrientation(angle);
3428 unitTarget->StopMoving();
3429 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3433 void Spell::EffectPickPocket(uint32 /*i*/)
3435 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3436 return;
3438 // victim must be creature and attackable
3439 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3440 return;
3442 // victim have to be alive and humanoid or undead
3443 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3445 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3447 if (chance > irand(0, 19))
3449 // Stealing successful
3450 //sLog.outDebug("Sending loot from pickpocket");
3451 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3453 else
3455 // Reveal action + get attack
3456 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3457 if (((Creature*)unitTarget)->AI())
3458 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3463 void Spell::EffectAddFarsight(uint32 i)
3465 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3466 int32 duration = GetSpellDuration(m_spellInfo);
3467 DynamicObject* dynObj = new DynamicObject;
3468 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))
3470 delete dynObj;
3471 return;
3473 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3474 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3475 m_caster->AddDynObject(dynObj);
3476 dynObj->GetMap()->Add(dynObj);
3477 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3478 ((Player*)m_caster)->SetFarSight(dynObj->GetGUID());
3481 void Spell::EffectSummonWild(uint32 i)
3483 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3484 if(!creature_entry)
3485 return;
3487 uint32 level = m_caster->getLevel();
3489 // level of creature summoned using engineering item based at engineering skill level
3490 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3492 ItemPrototype const *proto = m_CastItem->GetProto();
3493 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3495 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3496 if(skill202)
3498 level = skill202/5;
3503 // select center of summon position
3504 float center_x = m_targets.m_destX;
3505 float center_y = m_targets.m_destY;
3506 float center_z = m_targets.m_destZ;
3508 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3510 int32 amount = damage > 0 ? damage : 1;
3512 for(int32 count = 0; count < amount; ++count)
3514 float px, py, pz;
3515 // If dest location if present
3516 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3518 // Summon 1 unit in dest location
3519 if (count == 0)
3521 px = m_targets.m_destX;
3522 py = m_targets.m_destY;
3523 pz = m_targets.m_destZ;
3525 // Summon in random point all other units if location present
3526 else
3527 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3529 // Summon if dest location not present near caster
3530 else
3531 m_caster->GetClosePoint(px,py,pz,3.0f);
3533 int32 duration = GetSpellDuration(m_spellInfo);
3535 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3537 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3541 void Spell::EffectSummonGuardian(uint32 i)
3543 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3544 if(!pet_entry)
3545 return;
3547 // Jewelery statue case (totem like)
3548 if(m_spellInfo->SpellIconID==2056)
3550 EffectSummonTotem(i);
3551 return;
3554 // set timer for unsummon
3555 int32 duration = GetSpellDuration(m_spellInfo);
3557 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3558 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3559 // so this code hack in fact
3560 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3561 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3562 return; // find old guardian, ignore summon
3564 // in another case summon new
3565 uint32 level = m_caster->getLevel();
3567 // level of pet summoned using engineering item based at engineering skill level
3568 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3570 ItemPrototype const *proto = m_CastItem->GetProto();
3571 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3573 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3574 if(skill202)
3576 level = skill202/5;
3581 // select center of summon position
3582 float center_x = m_targets.m_destX;
3583 float center_y = m_targets.m_destY;
3584 float center_z = m_targets.m_destZ;
3586 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3588 int32 amount = damage > 0 ? damage : 1;
3590 for(int32 count = 0; count < amount; ++count)
3592 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3594 Map *map = m_caster->GetMap();
3595 uint32 pet_number = objmgr.GeneratePetNumber();
3596 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3598 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3599 delete spawnCreature;
3600 return;
3603 float px, py, pz;
3604 // If dest location if present
3605 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3607 // Summon 1 unit in dest location
3608 if (count == 0)
3610 px = m_targets.m_destX;
3611 py = m_targets.m_destY;
3612 pz = m_targets.m_destZ;
3614 // Summon in random point all other units if location present
3615 else
3616 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3618 // Summon if dest location not present near caster
3619 else
3620 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3622 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3624 if(!spawnCreature->IsPositionValid())
3626 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3627 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3628 delete spawnCreature;
3629 return;
3632 if(duration > 0)
3633 spawnCreature->SetDuration(duration);
3635 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3636 spawnCreature->setPowerType(POWER_MANA);
3637 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3638 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3639 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3640 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3641 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3642 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3643 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3645 spawnCreature->InitStatsForLevel(level);
3646 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3648 spawnCreature->AIM_Initialize();
3650 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3651 ((Player*)m_caster)->AddGuardian(spawnCreature);
3653 map->Add((Creature*)spawnCreature);
3657 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3659 if(!unitTarget)
3660 return;
3662 if(unitTarget->isInFlight())
3663 return;
3665 uint32 mapid = m_caster->GetMapId();
3666 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3668 float fx,fy,fz;
3669 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3671 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3672 ((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));
3673 else
3674 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3677 void Spell::EffectLearnSkill(uint32 i)
3679 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3680 return;
3682 if(damage < 0)
3683 return;
3685 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3686 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3687 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3690 void Spell::EffectAddHonor(uint32 /*i*/)
3692 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3693 return;
3695 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3697 // TODO: find formula for honor reward based on player's level!
3699 // now fixed only for level 70 players:
3700 if (((Player*)unitTarget)->getLevel() == 70)
3701 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3704 void Spell::EffectTradeSkill(uint32 /*i*/)
3706 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3707 return;
3708 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3709 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3710 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3713 void Spell::EffectEnchantItemPerm(uint32 i)
3715 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3716 return;
3717 if (!itemTarget)
3718 return;
3720 Player* p_caster = (Player*)m_caster;
3722 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3724 if (m_spellInfo->EffectMiscValue[i])
3726 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3728 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3729 if(!pEnchant)
3730 return;
3732 // item can be in trade slot and have owner diff. from caster
3733 Player* item_owner = itemTarget->GetOwner();
3734 if(!item_owner)
3735 return;
3737 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3738 sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3739 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3740 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3741 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3743 // remove old enchanting before applying new if equipped
3744 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3746 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3748 // add new enchanting if equipped
3749 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3753 void Spell::EffectEnchantItemTmp(uint32 i)
3755 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3756 return;
3758 Player* p_caster = (Player*)m_caster;
3760 if(!itemTarget)
3761 return;
3763 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3765 // Shaman Rockbiter Weapon
3766 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3768 int32 enchnting_damage = m_currentBasePoints[1]+1;
3770 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3771 // with already applied percent bonus from Elemental Weapons talent
3772 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3773 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3774 switch(enchnting_damage)
3776 // Rank 1
3777 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3778 // Rank 2
3779 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3780 case 5: enchant_id = 3025; break; // 20%
3781 // Rank 3
3782 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3783 case 7: enchant_id = 3027; break; // 20%
3784 // Rank 4
3785 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3786 case 10: enchant_id = 503; break; // 14%
3787 case 11: enchant_id = 3031; break; // 20%
3788 // Rank 5
3789 case 15: enchant_id = 3035; break; // 0%
3790 case 16: enchant_id = 1663; break; // 7%
3791 case 17: enchant_id = 3033; break; // 14%
3792 case 18: enchant_id = 3034; break; // 20%
3793 // Rank 6
3794 case 28: enchant_id = 3038; break; // 0%
3795 case 29: enchant_id = 683; break; // 7%
3796 case 31: enchant_id = 3036; break; // 14%
3797 case 33: enchant_id = 3037; break; // 20%
3798 // Rank 7
3799 case 40: enchant_id = 3041; break; // 0%
3800 case 42: enchant_id = 1664; break; // 7%
3801 case 45: enchant_id = 3039; break; // 14%
3802 case 48: enchant_id = 3040; break; // 20%
3803 // Rank 8
3804 case 49: enchant_id = 3044; break; // 0%
3805 case 52: enchant_id = 2632; break; // 7%
3806 case 55: enchant_id = 3042; break; // 14%
3807 case 58: enchant_id = 3043; break; // 20%
3808 // Rank 9
3809 case 62: enchant_id = 2633; break; // 0%
3810 case 66: enchant_id = 3018; break; // 7%
3811 case 70: enchant_id = 3019; break; // 14%
3812 case 74: enchant_id = 3020; break; // 20%
3813 default:
3814 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3815 return;
3819 if (!enchant_id)
3821 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3822 return;
3825 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3826 if(!pEnchant)
3828 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3829 return;
3832 // select enchantment duration
3833 uint32 duration;
3835 // rogue family enchantments exception by duration
3836 if(m_spellInfo->Id==38615)
3837 duration = 1800; // 30 mins
3838 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3839 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3840 duration = 3600; // 1 hour
3841 // shaman family enchantments
3842 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3843 duration = 1800; // 30 mins
3844 // other cases with this SpellVisual already selected
3845 else if(m_spellInfo->SpellVisual[0]==215)
3846 duration = 1800; // 30 mins
3847 // some fishing pole bonuses
3848 else if(m_spellInfo->SpellVisual[0]==563)
3849 duration = 600; // 10 mins
3850 // shaman rockbiter enchantments
3851 else if(m_spellInfo->SpellVisual[0]==0)
3852 duration = 1800; // 30 mins
3853 else if(m_spellInfo->Id==29702)
3854 duration = 300; // 5 mins
3855 else if(m_spellInfo->Id==37360)
3856 duration = 300; // 5 mins
3857 // default case
3858 else
3859 duration = 3600; // 1 hour
3861 // item can be in trade slot and have owner diff. from caster
3862 Player* item_owner = itemTarget->GetOwner();
3863 if(!item_owner)
3864 return;
3866 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3867 sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3868 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3869 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3870 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3872 // remove old enchanting before applying new if equipped
3873 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3875 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3877 // add new enchanting if equipped
3878 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3881 void Spell::EffectTameCreature(uint32 /*i*/)
3883 if(m_caster->GetPetGUID())
3884 return;
3886 if(!unitTarget)
3887 return;
3889 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3890 return;
3892 Creature* creatureTarget = (Creature*)unitTarget;
3894 if(creatureTarget->isPet())
3895 return;
3897 if(m_caster->getClass() != CLASS_HUNTER)
3898 return;
3900 // cast finish successfully
3901 //SendChannelUpdate(0);
3902 finish();
3904 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3906 // kill original creature
3907 creatureTarget->setDeathState(JUST_DIED);
3908 creatureTarget->RemoveCorpse();
3909 creatureTarget->SetHealth(0); // just for nice GM-mode view
3911 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
3913 // prepare visual effect for levelup
3914 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
3916 // add to world
3917 pet->GetMap()->Add((Creature*)pet);
3919 // visual effect for levelup
3920 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
3922 // caster have pet now
3923 m_caster->SetPet(pet);
3925 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3927 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3928 ((Player*)m_caster)->PetSpellInitialize();
3932 void Spell::EffectSummonPet(uint32 i)
3934 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3936 Pet *OldSummon = m_caster->GetPet();
3938 // if pet requested type already exist
3939 if( OldSummon )
3941 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3943 // pet in corpse state can't be summoned
3944 if( OldSummon->isDead() )
3945 return;
3947 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
3948 OldSummon->SetMapId(m_caster->GetMapId());
3950 float px, py, pz;
3951 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3953 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3954 m_caster->GetMap()->Add((Creature*)OldSummon);
3956 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
3958 ((Player*)m_caster)->PetSpellInitialize();
3960 return;
3963 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3964 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
3965 else
3966 return;
3969 Pet* NewSummon = new Pet;
3971 // petentry==0 for hunter "call pet" (current pet summoned if any)
3972 if(NewSummon->LoadPetFromDB(m_caster,petentry))
3974 if(NewSummon->getPetType()==SUMMON_PET)
3976 // Remove Demonic Sacrifice auras (known pet)
3977 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
3978 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
3980 if((*itr)->GetModifier()->m_miscvalue==2228)
3982 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
3983 itr = auraClassScripts.begin();
3985 else
3986 ++itr;
3990 return;
3993 // not error in case fail hunter call pet
3994 if(!petentry)
3996 delete NewSummon;
3997 return;
4000 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4002 if(!cInfo)
4004 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4005 delete NewSummon;
4006 return;
4009 Map *map = m_caster->GetMap();
4010 uint32 pet_number = objmgr.GeneratePetNumber();
4011 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4013 delete NewSummon;
4014 return;
4017 float px, py, pz;
4018 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4020 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4022 if(!NewSummon->IsPositionValid())
4024 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4025 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4026 delete NewSummon;
4027 return;
4030 uint32 petlevel = m_caster->getLevel();
4031 NewSummon->setPetType(SUMMON_PET);
4033 uint32 faction = m_caster->getFaction();
4034 if(m_caster->GetTypeId() == TYPEID_UNIT)
4036 if ( ((Creature*)m_caster)->isTotem() )
4037 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4038 else
4039 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4042 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4043 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4044 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4045 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4046 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4047 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4048 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4049 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4050 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4051 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4053 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4054 // this enables pet details window (Shift+P)
4056 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4057 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4059 NewSummon->InitStatsForLevel(petlevel);
4060 NewSummon->InitPetCreateSpells();
4062 if(NewSummon->getPetType()==SUMMON_PET)
4064 // Remove Demonic Sacrifice auras (new pet)
4065 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4066 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4068 if((*itr)->GetModifier()->m_miscvalue==2228)
4070 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4071 itr = auraClassScripts.begin();
4073 else
4074 ++itr;
4077 // generate new name for summon pet
4078 std::string new_name=objmgr.GeneratePetName(petentry);
4079 if(!new_name.empty())
4080 NewSummon->SetName(new_name);
4082 else if(NewSummon->getPetType()==HUNTER_PET)
4083 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4085 NewSummon->AIM_Initialize();
4086 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4087 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4089 map->Add((Creature*)NewSummon);
4091 m_caster->SetPet(NewSummon);
4092 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4094 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4096 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4097 ((Player*)m_caster)->PetSpellInitialize();
4101 void Spell::EffectLearnPetSpell(uint32 i)
4103 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4104 return;
4106 Player *_player = (Player*)m_caster;
4108 Pet *pet = _player->GetPet();
4109 if(!pet)
4110 return;
4111 if(!pet->isAlive())
4112 return;
4114 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4115 if(!learn_spellproto)
4116 return;
4118 pet->learnSpell(learn_spellproto->Id);
4120 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4121 _player->PetSpellInitialize();
4124 void Spell::EffectTaunt(uint32 /*i*/)
4126 // this effect use before aura Taunt apply for prevent taunt already attacking target
4127 // for spell as marked "non effective at already attacking target"
4128 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4130 if(unitTarget->getVictim()==m_caster)
4132 SendCastResult(SPELL_FAILED_DONT_REPORT);
4133 return;
4137 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4138 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4139 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4142 void Spell::EffectWeaponDmg(uint32 i)
4144 if(!unitTarget)
4145 return;
4146 if(!unitTarget->isAlive())
4147 return;
4149 // multiple weapon dmg effect workaround
4150 // execute only the last weapon damage
4151 // and handle all effects at once
4152 for (int j = 0; j < 3; j++)
4154 switch(m_spellInfo->Effect[j])
4156 case SPELL_EFFECT_WEAPON_DAMAGE:
4157 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4158 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4159 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4160 if (j < i) // we must calculate only at last weapon effect
4161 return;
4162 break;
4166 // some spell specific modifiers
4167 bool customBonusDamagePercentMod = false;
4168 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4169 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4170 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4171 bool normalized = false;
4173 int32 spell_bonus = 0; // bonus specific for spell
4174 switch(m_spellInfo->SpellFamilyName)
4176 case SPELLFAMILY_WARRIOR:
4178 // Whirlwind, single only spell with 2 weapon white damage apply if have
4179 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4181 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4182 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4184 // Devastate bonus and sunder armor refresh
4185 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4187 customBonusDamagePercentMod = true;
4188 bonusDamagePercentMod = 0.0f; // only applied if auras found
4190 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4191 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4193 SpellEntry const *proto = (*itr)->GetSpellProto();
4194 if(proto->SpellVisual[0] == 406 && proto->SpellIconID == 565)
4196 int32 duration = GetSpellDuration(proto);
4197 (*itr)->SetAuraDuration(duration);
4198 (*itr)->SendAuraUpdate(false);
4199 bonusDamagePercentMod += 1.0f; // +100%
4203 break;
4205 case SPELLFAMILY_ROGUE:
4207 // Ambush
4208 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4210 customBonusDamagePercentMod = true;
4211 bonusDamagePercentMod = 2.5f; // 250%
4213 // Mutilate (for each hand)
4214 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4216 bool found = false;
4217 // fast check
4218 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4219 found = true;
4220 // full aura scan
4221 else
4223 Unit::AuraMap const& auras = unitTarget->GetAuras();
4224 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4226 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4228 found = true;
4229 break;
4234 if(found)
4235 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4237 break;
4239 case SPELLFAMILY_PALADIN:
4241 // Seal of Command - receive benefit from Spell Damage and Healing
4242 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4244 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4245 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4247 break;
4249 case SPELLFAMILY_SHAMAN:
4251 // Skyshatter Harness item set bonus
4252 // Stormstrike
4253 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4255 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4256 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4258 // Stormstrike AP Buff
4259 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4261 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4262 break;
4269 int32 fixed_bonus = 0;
4270 for (int j = 0; j < 3; j++)
4272 switch(m_spellInfo->Effect[j])
4274 case SPELL_EFFECT_WEAPON_DAMAGE:
4275 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4276 fixed_bonus += CalculateDamage(j,unitTarget);
4277 break;
4278 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4279 fixed_bonus += CalculateDamage(j,unitTarget);
4280 normalized = true;
4281 break;
4282 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4283 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4285 // applied only to prev.effects fixed damage
4286 if(customBonusDamagePercentMod)
4287 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4288 else
4289 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4290 break;
4291 default:
4292 break; // not weapon damage effect, just skip
4296 // non-weapon damage
4297 int32 bonus = spell_bonus + fixed_bonus;
4299 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4300 if(bonus)
4302 UnitMods unitMod;
4303 switch(m_attackType)
4305 default:
4306 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4307 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4308 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4311 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4312 bonus = int32(bonus*weapon_total_pct);
4315 // + weapon damage with applied weapon% dmg to base weapon damage in call
4316 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4318 // total damage
4319 bonus = int32(bonus*totalDamagePercentMod);
4321 // prevent negative damage
4322 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4324 const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
4326 uint32 hitInfo = 0;
4327 VictimState victimState = VICTIMSTATE_NORMAL;
4328 uint32 blocked_dmg = 0;
4329 uint32 absorbed_dmg = 0;
4330 uint32 resisted_dmg = 0;
4331 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
4333 m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
4335 if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
4336 m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
4338 bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
4339 m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
4341 if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
4343 eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
4345 else
4347 cleanDamage.damage += eff_damage;
4348 eff_damage = 0;
4351 // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
4352 m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
4354 // Hemorrhage
4355 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4357 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4358 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4361 // Mangle (Cat): CP
4362 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4364 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4365 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4368 // take ammo
4369 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4371 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4373 // wands don't have ammo
4374 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4375 return;
4377 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4379 if(pItem->GetMaxStackCount()==1)
4381 // decrease durability for non-stackable throw weapon
4382 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4384 else
4386 // decrease items amount for stackable throw weapon
4387 uint32 count = 1;
4388 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4391 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4392 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4396 void Spell::EffectThreat(uint32 /*i*/)
4398 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4399 return;
4401 if(!unitTarget->CanHaveThreatList())
4402 return;
4404 unitTarget->AddThreat(m_caster, float(damage));
4407 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4409 if(!unitTarget)
4410 return;
4411 if(!unitTarget->isAlive())
4412 return;
4414 uint32 heal = m_caster->GetMaxHealth();
4416 int32 gain = unitTarget->ModifyHealth(heal);
4417 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
4419 m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
4422 void Spell::EffectInterruptCast(uint32 /*i*/)
4424 if(!unitTarget)
4425 return;
4426 if(!unitTarget->isAlive())
4427 return;
4429 // TODO: not all spells that used this effect apply cooldown at school spells
4430 // also exist case: apply cooldown to interrupted cast only and to all spells
4431 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4433 if (unitTarget->m_currentSpells[i])
4435 // check if we can interrupt spell
4436 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4438 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4439 unitTarget->InterruptSpell(i,false);
4445 void Spell::EffectSummonObjectWild(uint32 i)
4447 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4449 GameObject* pGameObj = new GameObject;
4451 WorldObject* target = focusObject;
4452 if( !target )
4453 target = m_caster;
4455 float x,y,z;
4456 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4458 x = m_targets.m_destX;
4459 y = m_targets.m_destY;
4460 z = m_targets.m_destZ;
4462 else
4463 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4465 Map *map = target->GetMap();
4467 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4468 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4470 delete pGameObj;
4471 return;
4474 int32 duration = GetSpellDuration(m_spellInfo);
4475 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4476 pGameObj->SetSpellId(m_spellInfo->Id);
4478 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4479 m_caster->AddGameObject(pGameObj);
4480 map->Add(pGameObj);
4482 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4484 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4486 Player *pl = (Player*)m_caster;
4487 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4488 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4490 uint32 team = ALLIANCE;
4492 if(pl->GetTeam() == team)
4493 team = HORDE;
4495 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4500 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4502 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4504 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4505 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4507 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4512 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4514 GameObject* linkedGO = new GameObject;
4515 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4516 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4518 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4519 linkedGO->SetSpellId(m_spellInfo->Id);
4521 m_caster->AddGameObject(linkedGO);
4522 map->Add(linkedGO);
4524 else
4526 delete linkedGO;
4527 linkedGO = NULL;
4528 return;
4533 void Spell::EffectScriptEffect(uint32 effIndex)
4535 // TODO: we must implement hunter pet summon at login there (spell 6962)
4537 // by spell id
4538 switch(m_spellInfo->Id)
4540 // Bending Shinbone
4541 case 8856:
4543 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4544 return;
4546 uint32 spell_id = 0;
4547 switch(urand(1,5))
4549 case 1: spell_id = 8854; break;
4550 default: spell_id = 8855; break;
4553 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4554 return;
4557 // Healthstone creating spells
4558 case 6201:
4559 case 6202:
4560 case 5699:
4561 case 11729:
4562 case 11730:
4563 case 27230:
4565 uint32 itemtype;
4566 uint32 rank = 0;
4567 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4568 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4570 if((*i)->GetId() == 18692)
4572 rank = 1;
4573 break;
4575 else if((*i)->GetId() == 18693)
4577 rank = 2;
4578 break;
4582 static uint32 const itypes[6][3] = {
4583 { 5512,19004,19005}, // Minor Healthstone
4584 { 5511,19006,19007}, // Lesser Healthstone
4585 { 5509,19008,19009}, // Healthstone
4586 { 5510,19010,19011}, // Greater Healthstone
4587 { 9421,19012,19013}, // Major Healthstone
4588 {22103,22104,22105} // Master Healthstone
4591 switch(m_spellInfo->Id)
4593 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4594 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4595 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4596 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4597 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4598 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4599 default:
4600 return;
4602 DoCreateItem( effIndex, itemtype );
4603 return;
4605 // Brittle Armor - need remove one 24575 Brittle Armor aura
4606 case 24590:
4607 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4608 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4609 return;
4610 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4611 case 26465:
4612 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4613 return;
4614 // Orb teleport spells
4615 case 25140:
4616 case 25143:
4617 case 25650:
4618 case 25652:
4619 case 29128:
4620 case 29129:
4621 case 35376:
4622 case 35727:
4624 if(!unitTarget)
4625 return;
4627 uint32 spellid;
4628 switch(m_spellInfo->Id)
4630 case 25140: spellid = 32571; break;
4631 case 25143: spellid = 32572; break;
4632 case 25650: spellid = 30140; break;
4633 case 25652: spellid = 30141; break;
4634 case 29128: spellid = 32568; break;
4635 case 29129: spellid = 32569; break;
4636 case 35376: spellid = 25649; break;
4637 case 35727: spellid = 35730; break;
4638 default:
4639 return;
4642 unitTarget->CastSpell(unitTarget,spellid,false);
4643 return;
4646 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4647 case 22539:
4648 case 22972:
4649 case 22975:
4650 case 22976:
4651 case 22977:
4652 case 22978:
4653 case 22979:
4654 case 22980:
4655 case 22981:
4656 case 22982:
4657 case 22983:
4658 case 22984:
4659 case 22985:
4661 if(!unitTarget || !unitTarget->isAlive())
4662 return;
4664 // Onyxia Scale Cloak
4665 if(unitTarget->GetDummyAura(22683))
4666 return;
4668 // Shadow Flame
4669 m_caster->CastSpell(unitTarget, 22682, true);
4670 return;
4672 break;
4674 // Summon Black Qiraji Battle Tank
4675 case 26656:
4677 if(!unitTarget)
4678 return;
4680 // Prevent stacking of mounts
4681 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4683 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4684 if (unitTarget->GetAreaId() == 3428)
4685 unitTarget->CastSpell(unitTarget, 25863, false);
4686 else
4687 unitTarget->CastSpell(unitTarget, 26655, false);
4688 break;
4690 // Piccolo of the Flaming Fire
4691 case 17512:
4693 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4694 return;
4695 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4696 break;
4699 // Dreaming Glory
4700 case 28698:
4702 if(!unitTarget)
4703 return;
4704 unitTarget->CastSpell(unitTarget, 28694, true);
4705 break;
4708 // Netherbloom
4709 case 28702:
4711 if(!unitTarget)
4712 return;
4713 // 25% chance of casting a random buff
4714 if(roll_chance_i(75))
4715 return;
4717 // triggered spells are 28703 to 28707
4718 // Note: some sources say, that there was the possibility of
4719 // receiving a debuff. However, this seems to be removed by a patch.
4720 const uint32 spellid = 28703;
4722 // don't overwrite an existing aura
4723 for(uint8 i=0; i<5; i++)
4724 if(unitTarget->HasAura(spellid+i, 0))
4725 return;
4726 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4727 break;
4730 // Nightmare Vine
4731 case 28720:
4733 if(!unitTarget)
4734 return;
4735 // 25% chance of casting Nightmare Pollen
4736 if(roll_chance_i(75))
4737 return;
4738 unitTarget->CastSpell(unitTarget, 28721, true);
4739 break;
4742 // Mirren's Drinking Hat
4743 case 29830:
4745 uint32 item = 0;
4746 switch ( urand(1,6) )
4748 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4749 case 4: case 5: item = 23585; break;// Stouthammer Lite
4750 case 6: item = 23586; break;// Aerie Peak Pale Ale
4752 if (item)
4753 DoCreateItem(effIndex,item);
4754 break;
4756 // Improved Sprint
4757 case 30918:
4759 // Removes snares and roots.
4760 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4761 Unit::AuraMap& Auras = unitTarget->GetAuras();
4762 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4764 next = iter;
4765 ++next;
4766 Aura *aur = iter->second;
4767 if (!aur->IsPositive()) //only remove negative spells
4769 // check for mechanic mask
4770 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4772 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4773 if(Auras.empty())
4774 break;
4775 else
4776 next = Auras.begin();
4780 break;
4782 case 41126: // Flame Crash
4784 if(!unitTarget)
4785 return;
4787 unitTarget->CastSpell(unitTarget, 41131, true);
4788 break;
4790 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4792 if(!unitTarget)
4793 return;
4795 unitTarget->CastSpell(unitTarget, 44870, true);
4796 break;
4799 // Goblin Weather Machine
4800 case 46203:
4802 if(!unitTarget)
4803 return;
4805 uint32 spellId;
4806 switch(rand()%4)
4808 case 0:
4809 spellId=46740;
4810 break;
4811 case 1:
4812 spellId=46739;
4813 break;
4814 case 2:
4815 spellId=46738;
4816 break;
4817 case 3:
4818 spellId=46736;
4819 break;
4821 unitTarget->CastSpell(unitTarget, spellId, true);
4822 break;
4824 //5,000 Gold
4825 case 46642:
4827 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4828 return;
4830 ((Player*)unitTarget)->ModifyMoney(50000000);
4832 break;
4836 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4838 switch(m_spellInfo->SpellFamilyFlags)
4840 // Judgement
4841 case 0x800000:
4843 if(!unitTarget || !unitTarget->isAlive())
4844 return;
4845 uint32 spellId2 = 0;
4847 // all seals have aura dummy
4848 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4849 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4851 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4853 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4854 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4855 continue;
4857 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4858 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4860 if(spellId2 <= 1)
4861 continue;
4863 // found, remove seal
4864 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4866 // Sanctified Judgement
4867 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4868 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4870 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4872 int32 chance = (*i)->GetModifier()->m_amount;
4873 if ( roll_chance_i(chance) )
4875 int32 mana = spellInfo->manaCost;
4876 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4877 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4878 mana = int32(mana* 0.8f);
4879 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4881 break;
4885 break;
4888 m_caster->CastSpell(unitTarget,spellId2,true);
4889 return;
4894 // normal DB scripted effect
4895 if(!unitTarget)
4896 return;
4898 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
4899 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
4902 void Spell::EffectSanctuary(uint32 /*i*/)
4904 if(!unitTarget)
4905 return;
4906 //unitTarget->CombatStop();
4908 unitTarget->CombatStop();
4909 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
4910 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4911 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
4913 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4917 void Spell::EffectAddComboPoints(uint32 /*i*/)
4919 if(!unitTarget)
4920 return;
4922 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4923 return;
4925 if(damage <= 0)
4926 return;
4928 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
4931 void Spell::EffectDuel(uint32 i)
4933 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4934 return;
4936 Player *caster = (Player*)m_caster;
4937 Player *target = (Player*)unitTarget;
4939 // caster or target already have requested duel
4940 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
4941 return;
4943 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4944 // Don't have to check the target's map since you cannot challenge someone across maps
4945 uint32 mapid = caster->GetMapId();
4946 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
4948 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4949 return;
4952 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
4953 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
4955 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4956 return;
4959 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
4960 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
4962 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4963 return;
4966 //CREATE DUEL FLAG OBJECT
4967 GameObject* pGameObj = new GameObject;
4969 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4971 Map *map = m_caster->GetMap();
4972 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4973 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
4974 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
4975 m_caster->GetPositionZ(),
4976 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
4978 delete pGameObj;
4979 return;
4982 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
4983 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
4984 int32 duration = GetSpellDuration(m_spellInfo);
4985 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4986 pGameObj->SetSpellId(m_spellInfo->Id);
4988 m_caster->AddGameObject(pGameObj);
4989 map->Add(pGameObj);
4990 //END
4992 // Send request
4993 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
4994 data << pGameObj->GetGUID();
4995 data << caster->GetGUID();
4996 caster->GetSession()->SendPacket(&data);
4997 target->GetSession()->SendPacket(&data);
4999 // create duel-info
5000 DuelInfo *duel = new DuelInfo;
5001 duel->initiator = caster;
5002 duel->opponent = target;
5003 duel->startTime = 0;
5004 duel->startTimer = 0;
5005 caster->duel = duel;
5007 DuelInfo *duel2 = new DuelInfo;
5008 duel2->initiator = caster;
5009 duel2->opponent = caster;
5010 duel2->startTime = 0;
5011 duel2->startTimer = 0;
5012 target->duel = duel2;
5014 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5015 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5018 void Spell::EffectStuck(uint32 /*i*/)
5020 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5021 return;
5023 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5024 return;
5026 Player* pTarget = (Player*)unitTarget;
5028 sLog.outDebug("Spell Effect: Stuck");
5029 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());
5031 if(pTarget->isInFlight())
5032 return;
5034 // homebind location is loaded always
5035 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5037 // Stuck spell trigger Hearthstone cooldown
5038 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5039 if(!spellInfo)
5040 return;
5041 Spell spell(pTarget,spellInfo,true,0);
5042 spell.SendSpellCooldown();
5045 void Spell::EffectSummonPlayer(uint32 /*i*/)
5047 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5048 return;
5050 // Evil Twin (ignore player summon, but hide this for summoner)
5051 if(unitTarget->GetDummyAura(23445))
5052 return;
5054 float x,y,z;
5055 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5057 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5059 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5060 data << uint64(m_caster->GetGUID()); // summoner guid
5061 data << uint32(m_caster->GetZoneId()); // summoner zone
5062 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5063 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5066 static ScriptInfo generateActivateCommand()
5068 ScriptInfo si;
5069 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5070 return si;
5073 void Spell::EffectActivateObject(uint32 effect_idx)
5075 if(!gameObjTarget)
5076 return;
5078 static ScriptInfo activateCommand = generateActivateCommand();
5080 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5082 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5085 void Spell::EffectApplyGlyph(uint32 i)
5087 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5088 return;
5090 Player *player = (Player*)m_caster;
5092 // remove old glyph
5093 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5095 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5097 player->RemoveAurasDueToSpell(old_gp->SpellId);
5098 player->SetGlyph(m_glyphIndex, 0);
5102 // apply new one
5103 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5105 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5107 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5109 if(gp->TypeFlags != gs->TypeFlags)
5111 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5112 return; // glyph slot missmatch
5116 player->CastSpell(m_caster, gp->SpellId, true);
5117 player->SetGlyph(m_glyphIndex, glyph);
5118 if(m_CastItem)
5119 player->DestroyItemCount(m_CastItem->GetEntry(), 1, true);
5124 void Spell::EffectSummonTotem(uint32 i)
5126 uint8 slot = 0;
5127 switch(m_spellInfo->EffectMiscValueB[i])
5129 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5130 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5131 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5132 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5133 // Battle standard case
5134 case SUMMON_TYPE_TOTEM: slot = 254; break;
5135 // jewelery statue case, like totem without slot
5136 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5137 default: return;
5140 if(slot < MAX_TOTEM)
5142 uint64 guid = m_caster->m_TotemSlot[slot];
5143 if(guid != 0)
5145 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5146 if(OldTotem && OldTotem->isTotem())
5147 ((Totem*)OldTotem)->UnSummon();
5151 uint32 team = 0;
5152 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5153 team = ((Player*)m_caster)->GetTeam();
5155 Totem* pTotem = new Totem;
5157 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5159 delete pTotem;
5160 return;
5163 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5165 float x,y,z;
5166 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5168 // totem must be at same Z in case swimming caster and etc.
5169 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5170 z = m_caster->GetPositionZ();
5172 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5174 if(slot < MAX_TOTEM)
5175 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5177 pTotem->SetOwner(m_caster->GetGUID());
5178 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5180 int32 duration=GetSpellDuration(m_spellInfo);
5181 if(Player* modOwner = m_caster->GetSpellModOwner())
5182 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5183 pTotem->SetDuration(duration);
5185 if (damage) // if not spell info, DB values used
5187 pTotem->SetMaxHealth(damage);
5188 pTotem->SetHealth(damage);
5191 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5192 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5194 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5195 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5197 pTotem->Summon(m_caster);
5199 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5201 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5202 data << uint8(slot);
5203 data << uint64(pTotem->GetGUID());
5204 data << uint32(duration);
5205 data << uint32(m_spellInfo->Id);
5206 ((Player*)m_caster)->SendDirectMessage(&data);
5210 void Spell::EffectEnchantHeldItem(uint32 i)
5212 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5213 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5214 return;
5216 Player* item_owner = (Player*)unitTarget;
5217 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5219 if(!item )
5220 return;
5222 // must be equipped
5223 if(!item ->IsEquipped())
5224 return;
5226 if (m_spellInfo->EffectMiscValue[i])
5228 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5229 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5230 if(!duration)
5231 duration = m_currentBasePoints[i]+1; //Base points after ..
5232 if(!duration)
5233 duration = 10; //10 seconds for enchants which don't have listed duration
5235 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5236 if(!pEnchant)
5237 return;
5239 // Always go to temp enchantment slot
5240 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5242 // Enchantment will not be applied if a different one already exists
5243 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5244 return;
5246 // Apply the temporary enchantment
5247 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5248 item_owner->ApplyEnchantment(item,slot,true);
5252 void Spell::EffectDisEnchant(uint32 /*i*/)
5254 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5255 return;
5257 Player* p_caster = (Player*)m_caster;
5258 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5259 return;
5261 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5263 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5265 // item will be removed at disenchanting end
5268 void Spell::EffectInebriate(uint32 /*i*/)
5270 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5271 return;
5273 Player *player = (Player*)unitTarget;
5274 uint16 currentDrunk = player->GetDrunkValue();
5275 uint16 drunkMod = damage * 256;
5276 if (currentDrunk + drunkMod > 0xFFFF)
5277 currentDrunk = 0xFFFF;
5278 else
5279 currentDrunk += drunkMod;
5280 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5283 void Spell::EffectFeedPet(uint32 i)
5285 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5286 return;
5288 Player *_player = (Player*)m_caster;
5290 if(!itemTarget)
5291 return;
5293 Pet *pet = _player->GetPet();
5294 if(!pet)
5295 return;
5297 if(!pet->isAlive())
5298 return;
5300 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5301 if(benefit <= 0)
5302 return;
5304 uint32 count = 1;
5305 _player->DestroyItemCount(itemTarget,count,true);
5306 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5308 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5311 void Spell::EffectDismissPet(uint32 /*i*/)
5313 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5314 return;
5316 Pet* pet = m_caster->GetPet();
5318 // not let dismiss dead pet
5319 if(!pet||!pet->isAlive())
5320 return;
5322 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5325 void Spell::EffectSummonObject(uint32 i)
5327 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5329 uint8 slot = 0;
5330 switch(m_spellInfo->Effect[i])
5332 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5333 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5334 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5335 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5336 default: return;
5339 uint64 guid = m_caster->m_ObjectSlot[slot];
5340 if(guid != 0)
5342 GameObject* obj = NULL;
5343 if( m_caster )
5344 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5346 if(obj) obj->Delete();
5347 m_caster->m_ObjectSlot[slot] = 0;
5350 GameObject* pGameObj = new GameObject;
5352 float rot2 = sin(m_caster->GetOrientation()/2);
5353 float rot3 = cos(m_caster->GetOrientation()/2);
5355 float x,y,z;
5356 // If dest location if present
5357 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5359 x = m_targets.m_destX;
5360 y = m_targets.m_destY;
5361 z = m_targets.m_destZ;
5363 // Summon in random point all other units if location present
5364 else
5365 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5367 Map *map = m_caster->GetMap();
5368 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5370 delete pGameObj;
5371 return;
5374 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5375 int32 duration = GetSpellDuration(m_spellInfo);
5376 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5377 pGameObj->SetSpellId(m_spellInfo->Id);
5378 m_caster->AddGameObject(pGameObj);
5380 map->Add(pGameObj);
5381 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5382 data << pGameObj->GetGUID();
5383 m_caster->SendMessageToSet(&data,true);
5385 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5388 void Spell::EffectResurrect(uint32 /*effIndex*/)
5390 if(!unitTarget)
5391 return;
5392 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5393 return;
5395 if(unitTarget->isAlive())
5396 return;
5397 if(!unitTarget->IsInWorld())
5398 return;
5400 switch (m_spellInfo->Id)
5402 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5403 case 8342:
5404 if (roll_chance_i(67))
5406 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5407 return;
5409 break;
5410 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5411 case 22999:
5412 if (roll_chance_i(50))
5414 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5415 return;
5417 break;
5418 default:
5419 break;
5422 Player* pTarget = ((Player*)unitTarget);
5424 if(pTarget->isRessurectRequested()) // already have one active request
5425 return;
5427 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5428 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5430 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5431 SendResurrectRequest(pTarget);
5434 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5436 if(!unitTarget || !unitTarget->isAlive())
5437 return;
5439 if( unitTarget->m_extraAttacks )
5440 return;
5442 unitTarget->m_extraAttacks = damage;
5445 void Spell::EffectParry(uint32 /*i*/)
5447 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5449 ((Player*)unitTarget)->SetCanParry(true);
5453 void Spell::EffectBlock(uint32 /*i*/)
5455 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5456 return;
5458 ((Player*)unitTarget)->SetCanBlock(true);
5461 void Spell::EffectMomentMove(uint32 i)
5463 if(unitTarget->isInFlight())
5464 return;
5466 if( m_spellInfo->rangeIndex== 1) //self range
5468 uint32 mapid = m_caster->GetMapId();
5469 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5471 // before caster
5472 float fx,fy,fz;
5473 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5474 float ox,oy,oz;
5475 unitTarget->GetPosition(ox,oy,oz);
5477 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5478 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5480 fx = fx2;
5481 fy = fy2;
5482 fz = fz2;
5483 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5486 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5487 ((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));
5488 else
5489 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5493 void Spell::EffectReputation(uint32 i)
5495 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5496 return;
5498 Player *_player = (Player*)unitTarget;
5500 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5502 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5504 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5506 if(!factionEntry)
5507 return;
5509 _player->ModifyFactionReputation(factionEntry,rep_change);
5512 void Spell::EffectQuestComplete(uint32 i)
5514 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5515 return;
5517 Player *_player = (Player*)m_caster;
5519 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5520 _player->AreaExploredOrEventHappens(quest_id);
5523 void Spell::EffectSelfResurrect(uint32 i)
5525 if(!unitTarget || unitTarget->isAlive())
5526 return;
5527 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5528 return;
5529 if(!unitTarget->IsInWorld())
5530 return;
5532 uint32 health = 0;
5533 uint32 mana = 0;
5535 // flat case
5536 if(damage < 0)
5538 health = uint32(-damage);
5539 mana = m_spellInfo->EffectMiscValue[i];
5541 // percent case
5542 else
5544 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5545 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5546 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5549 Player *plr = ((Player*)unitTarget);
5550 plr->ResurrectPlayer(0.0f);
5552 plr->SetHealth( health );
5553 plr->SetPower(POWER_MANA, mana );
5554 plr->SetPower(POWER_RAGE, 0 );
5555 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5557 plr->SpawnCorpseBones();
5559 plr->SaveToDB();
5562 void Spell::EffectSkinning(uint32 /*i*/)
5564 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5565 return;
5566 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5567 return;
5569 Creature* creature = (Creature*) unitTarget;
5570 int32 targetLevel = creature->getLevel();
5572 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5574 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5575 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5577 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5579 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5581 // Double chances for elites
5582 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5585 void Spell::EffectCharge(uint32 /*i*/)
5587 if(!unitTarget || !m_caster)
5588 return;
5590 float x, y, z;
5591 unitTarget->GetContactPoint(m_caster, x, y, z);
5592 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5593 ((Creature *)unitTarget)->StopMoving();
5595 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5596 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5598 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5599 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5601 // not all charge effects used in negative spells
5602 if ( !IsPositiveSpell(m_spellInfo->Id))
5603 m_caster->Attack(unitTarget,true);
5606 void Spell::EffectSummonCritter(uint32 i)
5608 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5609 return;
5610 Player* player = (Player*)m_caster;
5612 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5613 if(!pet_entry)
5614 return;
5616 Pet* old_critter = player->GetMiniPet();
5618 // for same pet just despawn
5619 if(old_critter && old_critter->GetEntry() == pet_entry)
5621 player->RemoveMiniPet();
5622 return;
5625 // despawn old pet before summon new
5626 if(old_critter)
5627 player->RemoveMiniPet();
5629 // summon new pet
5630 Pet* critter = new Pet(MINI_PET);
5632 Map *map = m_caster->GetMap();
5633 uint32 pet_number = objmgr.GeneratePetNumber();
5634 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5635 map, pet_entry, pet_number))
5637 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5638 delete critter;
5639 return;
5642 float x,y,z;
5643 // If dest location if present
5644 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5646 x = m_targets.m_destX;
5647 y = m_targets.m_destY;
5648 z = m_targets.m_destZ;
5650 // Summon if dest location not present near caster
5651 else
5652 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5654 critter->Relocate(x,y,z,m_caster->GetOrientation());
5656 if(!critter->IsPositionValid())
5658 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5659 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5660 delete critter;
5661 return;
5664 critter->SetOwnerGUID(m_caster->GetGUID());
5665 critter->SetCreatorGUID(m_caster->GetGUID());
5666 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5667 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5669 critter->AIM_Initialize();
5670 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5671 critter->SetMaxHealth(1);
5672 critter->SetHealth(1);
5673 critter->SetLevel(1);
5675 // set timer for unsummon
5676 int32 duration = GetSpellDuration(m_spellInfo);
5677 if(duration > 0)
5678 critter->SetDuration(duration);
5680 std::string name = player->GetName();
5681 name.append(petTypeSuffix[critter->getPetType()]);
5682 critter->SetName( name );
5683 player->SetMiniPet(critter);
5685 map->Add((Creature*)critter);
5688 void Spell::EffectKnockBack(uint32 i)
5690 if(!unitTarget || !m_caster)
5691 return;
5693 // Effect only works on players
5694 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5695 return;
5697 float vsin = sin(m_caster->GetAngle(unitTarget));
5698 float vcos = cos(m_caster->GetAngle(unitTarget));
5700 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5701 data.append(unitTarget->GetPackGUID());
5702 data << uint32(0); // Sequence
5703 data << float(vcos); // x direction
5704 data << float(vsin); // y direction
5705 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5706 data << float(damage/-10); // Z Movement speed (vertical)
5708 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5711 void Spell::EffectSendTaxi(uint32 i)
5713 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5714 return;
5716 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5717 if(!entry)
5718 return;
5720 std::vector<uint32> nodes;
5722 nodes.resize(2);
5723 nodes[0] = entry->from;
5724 nodes[1] = entry->to;
5726 uint32 mountid = 0;
5727 switch(m_spellInfo->Id)
5729 case 31606: //Stormcrow Amulet
5730 mountid = 17447;
5731 break;
5732 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5733 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5734 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5735 mountid = 22840;
5736 break;
5737 case 34905: //Stealth Flight
5738 mountid = 6851;
5739 break;
5742 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5746 void Spell::EffectPlayerPull(uint32 i)
5748 if(!unitTarget || !m_caster)
5749 return;
5751 // Effect only works on players
5752 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5753 return;
5755 float vsin = sin(unitTarget->GetAngle(m_caster));
5756 float vcos = cos(unitTarget->GetAngle(m_caster));
5758 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5759 data.append(unitTarget->GetPackGUID());
5760 data << uint32(0); // Sequence
5761 data << float(vcos); // x direction
5762 data << float(vsin); // y direction
5763 // Horizontal speed
5764 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5765 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5767 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5770 void Spell::EffectDispelMechanic(uint32 i)
5772 if(!unitTarget)
5773 return;
5775 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5777 Unit::AuraMap& Auras = unitTarget->GetAuras();
5778 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5780 next = iter;
5781 ++next;
5782 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5783 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5785 unitTarget->RemoveAurasDueToSpell(spell->Id);
5786 if(Auras.empty())
5787 break;
5788 else
5789 next = Auras.begin();
5792 return;
5795 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5797 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5798 return;
5799 Player *_player = (Player*)m_caster;
5800 Pet *pet = _player->GetPet();
5801 if(!pet)
5802 return;
5803 if(pet->isAlive())
5804 return;
5805 if(damage < 0)
5806 return;
5807 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5808 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5809 pet->setDeathState( ALIVE );
5810 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5811 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5813 pet->AIM_Initialize();
5815 _player->PetSpellInitialize();
5816 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5819 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5821 float mana = 0;
5822 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5824 if(!m_caster->m_TotemSlot[slot])
5825 continue;
5827 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5828 if(totem && totem->isTotem())
5830 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5831 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5832 if(spellInfo)
5833 mana += spellInfo->manaCost * damage / 100;
5834 ((Totem*)totem)->UnSummon();
5838 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5839 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5842 void Spell::EffectDurabilityDamage(uint32 i)
5844 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5845 return;
5847 int32 slot = m_spellInfo->EffectMiscValue[i];
5849 // FIXME: some spells effects have value -1/-2
5850 // Possibly its mean -1 all player equipped items and -2 all items
5851 if(slot < 0)
5853 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5854 return;
5857 // invalid slot value
5858 if(slot >= INVENTORY_SLOT_BAG_END)
5859 return;
5861 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5862 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5865 void Spell::EffectDurabilityDamagePCT(uint32 i)
5867 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5868 return;
5870 int32 slot = m_spellInfo->EffectMiscValue[i];
5872 // FIXME: some spells effects have value -1/-2
5873 // Possibly its mean -1 all player equipped items and -2 all items
5874 if(slot < 0)
5876 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5877 return;
5880 // invalid slot value
5881 if(slot >= INVENTORY_SLOT_BAG_END)
5882 return;
5884 if(damage <= 0)
5885 return;
5887 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5888 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
5891 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
5893 if(!unitTarget)
5894 return;
5896 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5899 void Spell::EffectTransmitted(uint32 effIndex)
5901 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
5903 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
5905 if (!goinfo)
5907 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
5908 return;
5911 float fx,fy,fz;
5913 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5915 fx = m_targets.m_destX;
5916 fy = m_targets.m_destY;
5917 fz = m_targets.m_destZ;
5919 //FIXME: this can be better check for most objects but still hack
5920 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
5922 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
5923 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5925 else
5927 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5928 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5929 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
5931 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5934 Map *cMap = m_caster->GetMap();
5936 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
5938 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
5939 { // but this is not proper, we really need to ignore not materialized objects
5940 SendCastResult(SPELL_FAILED_NOT_HERE);
5941 SendChannelUpdate(0);
5942 return;
5945 // replace by water level in this case
5946 fz = cMap->GetWaterLevel(fx,fy);
5948 // if gameobject is summoning object, it should be spawned right on caster's position
5949 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5951 m_caster->GetPosition(fx,fy,fz);
5954 GameObject* pGameObj = new GameObject;
5956 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5957 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5959 delete pGameObj;
5960 return;
5963 int32 duration = GetSpellDuration(m_spellInfo);
5965 switch(goinfo->type)
5967 case GAMEOBJECT_TYPE_FISHINGNODE:
5969 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
5970 // Orientation3
5971 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
5972 // Orientation4
5973 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
5974 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5976 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5977 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5978 int32 lastSec;
5979 switch(urand(0, 3))
5981 case 0: lastSec = 3; break;
5982 case 1: lastSec = 7; break;
5983 case 2: lastSec = 13; break;
5984 case 3: lastSec = 17; break;
5987 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
5988 break;
5990 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
5992 if(m_caster->GetTypeId()==TYPEID_PLAYER)
5994 pGameObj->AddUniqueUse((Player*)m_caster);
5995 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5997 break;
5999 case GAMEOBJECT_TYPE_FISHINGHOLE:
6000 case GAMEOBJECT_TYPE_CHEST:
6001 default:
6003 break;
6007 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6009 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6011 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6012 pGameObj->SetSpellId(m_spellInfo->Id);
6014 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6015 //m_caster->AddGameObject(pGameObj);
6016 //m_ObjToDel.push_back(pGameObj);
6018 cMap->Add(pGameObj);
6020 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6021 data << uint64(pGameObj->GetGUID());
6022 m_caster->SendMessageToSet(&data,true);
6024 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6026 GameObject* linkedGO = new GameObject;
6027 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6028 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6030 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6031 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6032 linkedGO->SetSpellId(m_spellInfo->Id);
6033 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6035 linkedGO->GetMap()->Add(linkedGO);
6037 else
6039 delete linkedGO;
6040 linkedGO = NULL;
6041 return;
6046 void Spell::EffectProspecting(uint32 /*i*/)
6048 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6049 return;
6051 Player* p_caster = (Player*)m_caster;
6052 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6053 return;
6055 if(itemTarget->GetCount() < 5)
6056 return;
6058 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6060 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6061 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6062 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6065 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6068 void Spell::EffectSkill(uint32 /*i*/)
6070 sLog.outDebug("WORLD: SkillEFFECT");
6073 void Spell::EffectSummonDemon(uint32 i)
6075 float px = m_targets.m_destX;
6076 float py = m_targets.m_destY;
6077 float pz = m_targets.m_destZ;
6079 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6080 if (!Charmed)
6081 return;
6083 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6084 Charmed->SetLevel(m_caster->getLevel());
6086 // TODO: Add damage/mana/hp according to level
6088 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6090 // Enslave demon effect, without mana cost and cooldown
6091 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6093 // Inferno effect
6094 Charmed->CastSpell(Charmed, 22703, true, 0);
6098 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6099 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6100 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6101 This is why we use a half sec delay between the visual effect and the resurrection itself */
6102 void Spell::EffectSpiritHeal(uint32 /*i*/)
6105 if(!unitTarget || unitTarget->isAlive())
6106 return;
6107 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6108 return;
6109 if(!unitTarget->IsInWorld())
6110 return;
6112 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6113 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6114 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6115 ((Player*)unitTarget)->SpawnCorpseBones();
6119 // remove insignia spell effect
6120 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6122 sLog.outDebug("Effect: SkinPlayerCorpse");
6123 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6124 return;
6126 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6129 void Spell::EffectStealBeneficialBuff(uint32 i)
6131 sLog.outDebug("Effect: StealBeneficialBuff");
6133 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6134 return;
6136 std::vector <Aura *> steal_list;
6137 // Create dispel mask by dispel type
6138 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6139 Unit::AuraMap const& auras = unitTarget->GetAuras();
6140 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6142 Aura *aur = (*itr).second;
6143 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6145 // Need check for passive? this
6146 if (aur->IsPositive() && !aur->IsPassive())
6147 steal_list.push_back(aur);
6150 // Ok if exist some buffs for dispel try dispel it
6151 if (!steal_list.empty())
6153 std::list < std::pair<uint32,uint64> > success_list;
6154 int32 list_size = steal_list.size();
6155 // Dispell N = damage buffs (or while exist buffs for dispel)
6156 for (int32 count=0; count < damage && list_size > 0; ++count)
6158 // Random select buff for dispel
6159 Aura *aur = steal_list[urand(0, list_size-1)];
6160 // Not use chance for steal
6161 // TODO possible need do it
6162 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6164 // Remove buff from list for prevent doubles
6165 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6167 Aura *stealed = *j;
6168 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6170 j = steal_list.erase(j);
6171 --list_size;
6173 else
6174 ++j;
6177 // Really try steal and send log
6178 if (!success_list.empty())
6180 int32 count = success_list.size();
6181 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6182 data.append(unitTarget->GetPackGUID()); // Victim GUID
6183 data.append(m_caster->GetPackGUID()); // Caster GUID
6184 data << uint32(m_spellInfo->Id); // Dispell spell id
6185 data << uint8(0); // not used
6186 data << uint32(count); // count
6187 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6189 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6190 data << uint32(spellInfo->Id); // Spell Id
6191 data << uint8(0); // 0 - steals !=0 transfers
6192 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6194 m_caster->SendMessageToSet(&data, true);
6199 void Spell::EffectKillCredit(uint32 i)
6201 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6202 return;
6204 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6207 void Spell::EffectQuestFail(uint32 i)
6209 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6210 return;
6212 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);