* Fix some warlock talent work
[getmangos.git] / src / game / SpellEffects.cpp
blob4f8baefc4436d97d7799bc46608470977e429978
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"
56 #include "ScriptCalls.h"
58 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
60 &Spell::EffectNULL, // 0
61 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
102 &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
103 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
107 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
120 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
126 &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
127 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
134 &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
135 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
148 &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
149 &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
150 &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
151 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
154 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
158 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
170 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
173 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
185 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
192 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
193 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
199 &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
200 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
202 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
205 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
206 &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
207 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
209 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
210 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
211 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
213 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
216 void Spell::EffectNULL(uint32 /*i*/)
218 sLog.outDebug("WORLD: Spell Effect DUMMY");
221 void Spell::EffectUnused(uint32 /*i*/)
223 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
226 void Spell::EffectResurrectNew(uint32 i)
228 if(!unitTarget || unitTarget->isAlive())
229 return;
231 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
232 return;
234 if(!unitTarget->IsInWorld())
235 return;
237 Player* pTarget = ((Player*)unitTarget);
239 if(pTarget->isRessurectRequested()) // already have one active request
240 return;
242 uint32 health = damage;
243 uint32 mana = m_spellInfo->EffectMiscValue[i];
244 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
245 SendResurrectRequest(pTarget);
248 void Spell::EffectInstaKill(uint32 /*i*/)
250 if( !unitTarget || !unitTarget->isAlive() )
251 return;
253 // Demonic Sacrifice
254 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
256 uint32 entry = unitTarget->GetEntry();
257 uint32 spellID;
258 switch(entry)
260 case 416: spellID=18789; break; //imp
261 case 417: spellID=18792; break; //fellhunter
262 case 1860: spellID=18790; break; //void
263 case 1863: spellID=18791; break; //succubus
264 case 17252: spellID=35701; break; //fellguard
265 default:
266 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
267 return;
270 m_caster->CastSpell(m_caster,spellID,true);
273 if(m_caster==unitTarget) // prevent interrupt message
274 finish();
276 uint32 health = unitTarget->GetHealth();
277 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
280 void Spell::EffectEnvirinmentalDMG(uint32 i)
282 uint32 absorb = 0;
283 uint32 resist = 0;
285 // Note: this hack with damage replace required until GO casting not implemented
286 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
287 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
288 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
290 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
292 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
293 if(m_caster->GetTypeId() == TYPEID_PLAYER)
294 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
297 void Spell::EffectSchoolDMG(uint32 effect_idx)
299 if( unitTarget && unitTarget->isAlive())
301 switch(m_spellInfo->SpellFamilyName)
303 case SPELLFAMILY_GENERIC:
305 //Gore
306 if(m_spellInfo->SpellIconID == 2269 )
308 damage+= rand()%2 ? damage : 0;
311 switch(m_spellInfo->Id) // better way to check unknown
313 // Meteor like spells (divided damage to targets)
314 case 24340: case 26558: case 28884: // Meteor
315 case 36837: case 38903: case 41276: // Meteor
316 case 26789: // Shard of the Fallen Star
317 case 31436: // Malevolent Cleave
318 case 35181: // Dive Bomb
319 case 40810: case 43267: case 43268: // Saber Lash
320 case 42384: // Brutal Swipe
321 case 45150: // Meteor Slash
323 uint32 count = 0;
324 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
325 if(ihit->effectMask & (1<<effect_idx))
326 ++count;
328 damage /= count; // divide to all targets
329 break;
331 // percent from health with min
332 case 25599: // Thundercrash
334 damage = unitTarget->GetHealth() / 2;
335 if(damage < 200)
336 damage = 200;
337 break;
340 break;
343 case SPELLFAMILY_MAGE:
345 // Arcane Blast
346 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
348 m_caster->CastSpell(m_caster,36032,true);
350 break;
352 case SPELLFAMILY_WARRIOR:
354 // Bloodthirst
355 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
357 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
359 // Shield Slam
360 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
361 damage += int32(m_caster->GetShieldBlockValue());
362 // Victory Rush
363 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
365 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
366 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
368 break;
370 case SPELLFAMILY_WARLOCK:
372 // Incinerate Rank 1 & 2
373 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
375 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
376 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
377 damage += int32(damage*0.25);
379 break;
381 case SPELLFAMILY_DRUID:
383 // Ferocious Bite
384 if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
386 // converts each extra point of energy into ($f1+$AP/630) additional damage
387 float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
388 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
389 m_caster->SetPower(POWER_ENERGY,0);
391 // Rake
392 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
394 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
396 // Swipe
397 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
399 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
401 // Starfire
402 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
404 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
405 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
407 // Starfire Bonus (caster)
408 switch((*i)->GetModifier()->m_miscvalue)
410 case 5481: // Nordrassil Regalia - bonus
412 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
413 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
415 // Moonfire or Insect Swarm (target debuff from any casters)
416 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
418 int32 mod = (*i)->GetModifier()->m_amount;
419 damage += damage*mod/100;
420 break;
423 break;
425 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
427 damage += (*i)->GetModifier()->m_amount;
428 break;
433 //Mangle Bonus for the initial damage of Lacerate and Rake
434 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
435 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
437 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
438 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
439 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
441 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
442 break;
445 break;
447 case SPELLFAMILY_ROGUE:
449 // Envenom
450 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
452 // consume from stack dozes not more that have combo-points
453 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
455 // count consumed deadly poison doses at target
456 uint32 doses = 0;
458 // remove consumed poison doses
459 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
460 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
462 // Deadly poison (only attacker applied)
463 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
464 (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
466 --combo;
467 ++doses;
469 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
471 itr = auras.begin();
473 else
474 ++itr;
477 damage *= doses;
478 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
480 // Eviscerate and Envenom Bonus Damage (item set effect)
481 if(m_caster->GetDummyAura(37169))
482 damage += ((Player*)m_caster)->GetComboPoints()*40;
485 // Eviscerate
486 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
488 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
490 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
492 // Eviscerate and Envenom Bonus Damage (item set effect)
493 if(m_caster->GetDummyAura(37169))
494 damage += combo*40;
497 break;
499 case SPELLFAMILY_HUNTER:
501 // Mongoose Bite
502 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
504 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
506 // Arcane Shot
507 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
509 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
511 // Steady Shot
512 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
514 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
515 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
517 //Explosive Trap Effect
518 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
520 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
522 break;
524 case SPELLFAMILY_PALADIN:
526 //Judgement of Vengeance
527 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
529 uint32 stacks = 0;
530 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
531 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
532 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
533 ++stacks;
534 if(!stacks)
535 //No damage if the target isn't affected by this
536 damage = -1;
537 else
538 damage *= stacks;
540 break;
544 if(damage >= 0)
545 m_damage+= damage;
549 void Spell::EffectDummy(uint32 i)
551 if(!unitTarget && !gameObjTarget && !itemTarget)
552 return;
554 // selection by spell family
555 switch(m_spellInfo->SpellFamilyName)
557 case SPELLFAMILY_GENERIC:
559 switch(m_spellInfo->Id )
561 case 8063: // Deviate Fish
563 if(m_caster->GetTypeId() != TYPEID_PLAYER)
564 return;
566 uint32 spell_id = 0;
567 switch(urand(1,5))
569 case 1: spell_id = 8064; break; // Sleepy
570 case 2: spell_id = 8065; break; // Invigorate
571 case 3: spell_id = 8066; break; // Shrink
572 case 4: spell_id = 8067; break; // Party Time!
573 case 5: spell_id = 8068; break; // Healthy Spirit
575 m_caster->CastSpell(m_caster,spell_id,true,NULL);
576 return;
578 case 8213: // Savory Deviate Delight
580 if(m_caster->GetTypeId() != TYPEID_PLAYER)
581 return;
583 uint32 spell_id = 0;
584 switch(urand(1,2))
586 // Flip Out - ninja
587 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
588 // Yaaarrrr - pirate
589 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
591 m_caster->CastSpell(m_caster,spell_id,true,NULL);
592 return;
594 case 8593: // Symbol of life (restore creature to life)
595 case 31225: // Shimmering Vessel (restore creature to life)
597 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
598 return;
599 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
600 return;
602 case 12162: // Deep wounds
603 case 12850: // (now good common check for this spells)
604 case 12868:
606 if(!unitTarget)
607 return;
609 float damage;
610 // DW should benefit of attack power, damage percent mods etc.
611 // TODO: check if using offhand damage is correct and if it should be divided by 2
612 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
613 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
614 else
615 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
617 switch (m_spellInfo->Id)
619 case 12850: damage *= 0.2f; break;
620 case 12162: damage *= 0.4f; break;
621 case 12868: damage *= 0.6f; break;
622 default:
623 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
624 return;
627 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
628 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
629 return;
631 case 12975: //Last Stand
633 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
634 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
635 return;
637 case 13120: // net-o-matic
639 if(!unitTarget)
640 return;
642 uint32 spell_id = 0;
644 uint32 roll = urand(0, 99);
646 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
647 spell_id = 16566;
648 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
649 spell_id = 13119;
650 else // normal root
651 spell_id = 13099;
653 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
654 return;
656 case 13567: // Dummy Trigger
658 // can be used for different aura triggering, so select by aura
659 if(!m_triggeredByAuraSpell || !unitTarget)
660 return;
662 switch(m_triggeredByAuraSpell->Id)
664 case 26467: // Persistent Shield
665 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
666 break;
667 default:
668 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
669 break;
671 return;
673 case 14185: // Preparation Rogue
675 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
676 return;
678 //immediately finishes the cooldown on certain Rogue abilities
679 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
680 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
682 uint32 classspell = itr->first;
683 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
685 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
687 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
689 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
690 data << uint32(classspell);
691 data << uint64(m_caster->GetGUID());
692 ((Player*)m_caster)->GetSession()->SendPacket(&data);
695 return;
697 case 15998: // Capture Worg Pup
698 case 29435: // Capture Female Kaliri Hatchling
700 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
701 return;
703 Creature* creatureTarget = (Creature*)unitTarget;
704 creatureTarget->setDeathState(JUST_DIED);
705 creatureTarget->RemoveCorpse();
706 creatureTarget->SetHealth(0); // just for nice GM-mode view
707 return;
709 case 16589: // Noggenfogger Elixir
711 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
712 return;
714 uint32 spell_id = 0;
715 switch(urand(1,3))
717 case 1: spell_id = 16595; break;
718 case 2: spell_id = 16593; break;
719 default:spell_id = 16591; break;
722 m_caster->CastSpell(m_caster,spell_id,true,NULL);
723 return;
725 case 17251: // Spirit Healer Res
727 if(!unitTarget || !m_originalCaster)
728 return;
730 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
732 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
733 data << unitTarget->GetGUID();
734 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
736 return;
738 case 17271: // Test Fetid Skull
740 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
741 return;
743 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
745 m_caster->CastSpell(m_caster,spell_id,true,NULL);
746 return;
748 case 20577: // Cannibalize
749 if (unitTarget)
750 m_caster->CastSpell(m_caster,20578,false,NULL);
751 return;
752 case 23019: // Crystal Prison Dummy DND
754 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
755 return;
757 Creature* creatureTarget = (Creature*)unitTarget;
758 if(creatureTarget->isPet())
759 return;
761 creatureTarget->setDeathState(JUST_DIED);
762 creatureTarget->RemoveCorpse();
763 creatureTarget->SetHealth(0); // just for nice GM-mode view
765 GameObject* pGameObj = new GameObject;
767 Map *map = creatureTarget->GetMap();
769 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
770 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
771 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
773 delete pGameObj;
774 return;
777 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
778 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
779 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
780 pGameObj->SetSpellId(m_spellInfo->Id);
782 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
783 map->Add(pGameObj);
785 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
786 data << uint64(pGameObj->GetGUID());
787 m_caster->SendMessageToSet(&data,true);
789 return;
791 case 23074: // Arc. Dragonling
792 if (!m_CastItem) return;
793 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
794 return;
795 case 23075: // Mithril Mechanical Dragonling
796 if (!m_CastItem) return;
797 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
798 return;
799 case 23076: // Mechanical Dragonling
800 if (!m_CastItem) return;
801 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
802 return;
803 case 23133: // Gnomish Battle Chicken
804 if (!m_CastItem) return;
805 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
806 return;
807 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
809 int32 r = irand(0, 119);
810 if ( r < 20 ) // 1/6 polymorph
811 m_caster->CastSpell(m_caster,23444,true);
812 else if ( r < 100 ) // 4/6 evil twin
813 m_caster->CastSpell(m_caster,23445,true);
814 else // 1/6 miss the target
815 m_caster->CastSpell(m_caster,36902,true);
816 return;
818 case 23453: // Ultrasafe Transporter: Gadgetzan
819 if ( roll_chance_i(50) ) // success
820 m_caster->CastSpell(m_caster,23441,true);
821 else // failure
822 m_caster->CastSpell(m_caster,23446,true);
823 return;
824 case 23645: // Hourglass Sand
825 m_caster->RemoveAurasDueToSpell(23170);
826 return;
827 case 23725: // Gift of Life (warrior bwl trinket)
828 m_caster->CastSpell(m_caster,23782,true);
829 m_caster->CastSpell(m_caster,23783,true);
830 return;
831 case 25860: // Reindeer Transformation
833 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
834 return;
836 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
837 float speed = m_caster->GetSpeedRate(MOVE_RUN);
839 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
841 //5 different spells used depending on mounted speed and if mount can fly or not
842 if (flyspeed >= 4.1f)
843 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
844 else if (flyspeed >= 3.8f)
845 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
846 else if (flyspeed >= 1.6f)
847 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
848 else if (speed >= 2.0f)
849 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
850 else
851 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
853 return;
855 //case 26074: // Holiday Cheer
856 // return; -- implemented at client side
857 case 28006: // Arcane Cloaking
859 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
860 m_caster->CastSpell(unitTarget,29294,true);
861 return;
863 case 28730: // Arcane Torrent (Mana)
865 int32 count = 0;
866 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
867 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
868 if ((*i)->GetId() == 28734)
869 ++count;
870 if (count)
872 m_caster->RemoveAurasDueToSpell(28734);
873 int32 bp = damage * count;
874 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
876 return;
878 case 29200: // Purify Helboar Meat
880 if( m_caster->GetTypeId() != TYPEID_PLAYER )
881 return;
883 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
885 m_caster->CastSpell(m_caster,spell_id,true,NULL);
886 return;
888 case 29858: // Soulshatter
889 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
890 m_caster->CastSpell(unitTarget,32835,true);
891 return;
892 case 30458: // Nigh Invulnerability
893 if (!m_CastItem) return;
894 if(roll_chance_i(86)) // success
895 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
896 else // backfire in 14% casts
897 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
898 return;
899 case 30507: // Poultryizer
900 if (!m_CastItem) return;
901 if(roll_chance_i(80)) // success
902 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
903 else // backfire 20%
904 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
905 return;
906 case 33060: // Make a Wish
908 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
909 return;
911 uint32 spell_id = 0;
913 switch(urand(1,5))
915 case 1: spell_id = 33053; break;
916 case 2: spell_id = 33057; break;
917 case 3: spell_id = 33059; break;
918 case 4: spell_id = 33062; break;
919 case 5: spell_id = 33064; break;
922 m_caster->CastSpell(m_caster,spell_id,true,NULL);
923 return;
925 case 35745:
927 uint32 spell_id;
928 switch(m_caster->GetAreaId())
930 case 3900: spell_id = 35743; break;
931 case 3742: spell_id = 35744; break;
932 default: return;
935 m_caster->CastSpell(m_caster,spell_id,true);
936 return;
938 case 37674: // Chaos Blast
940 if(!unitTarget)
941 return;
943 int32 basepoints0 = 100;
944 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
945 return;
947 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
949 // selecting one from Bloodstained Fortune item
950 uint32 newitemid;
951 switch(urand(1,20))
953 case 1: newitemid = 32688; break;
954 case 2: newitemid = 32689; break;
955 case 3: newitemid = 32690; break;
956 case 4: newitemid = 32691; break;
957 case 5: newitemid = 32692; break;
958 case 6: newitemid = 32693; break;
959 case 7: newitemid = 32700; break;
960 case 8: newitemid = 32701; break;
961 case 9: newitemid = 32702; break;
962 case 10: newitemid = 32703; break;
963 case 11: newitemid = 32704; break;
964 case 12: newitemid = 32705; break;
965 case 13: newitemid = 32706; break;
966 case 14: newitemid = 32707; break;
967 case 15: newitemid = 32708; break;
968 case 16: newitemid = 32709; break;
969 case 17: newitemid = 32710; break;
970 case 18: newitemid = 32711; break;
971 case 19: newitemid = 32712; break;
972 case 20: newitemid = 32713; break;
973 default:
974 return;
977 DoCreateItem(i,newitemid);
978 return;
980 // Demon Broiled Surprise
981 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
982 case 43723:
984 if (m_caster->GetTypeId() != TYPEID_PLAYER)
985 return;
987 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
988 return;
991 case 44875: // Complete Raptor Capture
993 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
994 return;
996 Creature* creatureTarget = (Creature*)unitTarget;
998 creatureTarget->setDeathState(JUST_DIED);
999 creatureTarget->RemoveCorpse();
1000 creatureTarget->SetHealth(0); // just for nice GM-mode view
1002 //cast spell Raptor Capture Credit
1003 m_caster->CastSpell(m_caster,42337,true,NULL);
1004 return;
1006 case 37573: //Temporal Phase Modulator
1008 if(!unitTarget)
1009 return;
1011 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1012 if(!tempSummon)
1013 return;
1015 uint32 health = tempSummon->GetHealth();
1016 const uint32 entry_list[6] = {21821, 21820, 21817};
1018 float x = tempSummon->GetPositionX();
1019 float y = tempSummon->GetPositionY();
1020 float z = tempSummon->GetPositionZ();
1021 float o = tempSummon->GetOrientation();
1023 tempSummon->UnSummon();
1025 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1026 if (!pCreature)
1027 return;
1029 pCreature->SetHealth(health);
1031 if(pCreature->AI())
1032 pCreature->AI()->AttackStart(m_caster);
1034 return;
1036 case 34665: //Administer Antidote
1038 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1039 return;
1041 if(!unitTarget)
1042 return;
1044 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1045 if(!tempSummon)
1046 return;
1048 uint32 health = tempSummon->GetHealth();
1050 float x = tempSummon->GetPositionX();
1051 float y = tempSummon->GetPositionY();
1052 float z = tempSummon->GetPositionZ();
1053 float o = tempSummon->GetOrientation();
1054 tempSummon->UnSummon();
1056 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1057 if (!pCreature)
1058 return;
1060 pCreature->SetHealth(health);
1061 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1063 if (pCreature->AI())
1064 pCreature->AI()->AttackStart(m_caster);
1066 return;
1068 case 44997: // Converting Sentry
1070 //Converted Sentry Credit
1071 m_caster->CastSpell(m_caster, 45009, true);
1072 return;
1074 case 45030: // Impale Emissary
1076 // Emissary of Hate Credit
1077 m_caster->CastSpell(m_caster, 45088, true);
1078 return;
1080 case 50243: // Teach Language
1082 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1083 return;
1085 // spell has a 1/3 chance to trigger one of the below
1086 if(roll_chance_i(66))
1087 return;
1088 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1090 // 1000001 - gnomish binary
1091 m_caster->CastSpell(m_caster, 50242, true);
1093 else
1095 // 01001000 - goblin binary
1096 m_caster->CastSpell(m_caster, 50246, true);
1099 return;
1101 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1103 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1104 return;
1106 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1107 bg->EventPlayerDroppedFlag((Player*)m_caster);
1109 m_caster->CastSpell(m_caster, 30452, true, NULL);
1110 return;
1114 //All IconID Check in there
1115 switch(m_spellInfo->SpellIconID)
1117 // Berserking (troll racial traits)
1118 case 1661:
1120 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1121 int32 melee_mod = 10;
1122 if (healthPerc <= 40)
1123 melee_mod = 30;
1124 if (healthPerc < 100 && healthPerc > 40)
1125 melee_mod = 10+(100-healthPerc)/3;
1127 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1128 int32 hasteModBasePoints1 = (5-melee_mod);
1129 int32 hasteModBasePoints2 = 5;
1131 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1132 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1133 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1134 return;
1137 break;
1139 case SPELLFAMILY_MAGE:
1140 switch(m_spellInfo->Id )
1142 case 11958: // Cold Snap
1144 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1145 return;
1147 // immediately finishes the cooldown on Frost spells
1148 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1149 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1151 if (itr->second->state == PLAYERSPELL_REMOVED)
1152 continue;
1154 uint32 classspell = itr->first;
1155 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1157 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1158 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1159 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1161 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1163 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1164 data << uint32(classspell);
1165 data << uint64(m_caster->GetGUID());
1166 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1169 return;
1171 case 32826:
1173 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1175 //Polymorph Cast Visual Rank 1
1176 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1177 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1179 return;
1182 break;
1183 case SPELLFAMILY_WARRIOR:
1184 // Charge
1185 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
1187 int32 chargeBasePoints0 = damage;
1188 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1189 return;
1191 // Execute
1192 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1194 if(!unitTarget)
1195 return;
1197 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1198 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1199 m_caster->SetPower(POWER_RAGE,0);
1200 return;
1202 if(m_spellInfo->Id==21977) //Warrior's Wrath
1204 if(!unitTarget)
1205 return;
1207 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1208 return;
1210 break;
1211 case SPELLFAMILY_WARLOCK:
1212 //Life Tap (only it have this with dummy effect)
1213 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1215 float cost = m_currentBasePoints[0]+1;
1217 if(Player* modOwner = m_caster->GetSpellModOwner())
1218 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1220 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1222 if(int32(m_caster->GetHealth()) > dmg)
1224 // Shouldn't Appear in Combat Log
1225 m_caster->ModifyHealth(-dmg);
1227 int32 mana = dmg;
1229 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1230 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1232 // only Imp. Life Tap have this in combination with dummy aura
1233 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1234 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1237 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1239 // Mana Feed
1240 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1241 manaFeedVal = manaFeedVal * mana / 100;
1242 if(manaFeedVal > 0)
1243 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1245 else
1246 SendCastResult(SPELL_FAILED_FIZZLE);
1247 return;
1249 break;
1250 case SPELLFAMILY_PRIEST:
1251 switch(m_spellInfo->Id )
1253 case 28598: // Touch of Weakness triggered spell
1255 if(!unitTarget || !m_triggeredByAuraSpell)
1256 return;
1258 uint32 spellid = 0;
1259 switch(m_triggeredByAuraSpell->Id)
1261 case 2652: spellid = 2943; break; // Rank 1
1262 case 19261: spellid = 19249; break; // Rank 2
1263 case 19262: spellid = 19251; break; // Rank 3
1264 case 19264: spellid = 19252; break; // Rank 4
1265 case 19265: spellid = 19253; break; // Rank 5
1266 case 19266: spellid = 19254; break; // Rank 6
1267 case 25461: spellid = 25460; break; // Rank 7
1268 default:
1269 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1270 return;
1272 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1273 return;
1276 break;
1277 case SPELLFAMILY_DRUID:
1278 switch(m_spellInfo->Id )
1280 case 5420: // Tree of Life passive
1282 // Tree of Life area effect
1283 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1284 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1285 return;
1288 break;
1289 case SPELLFAMILY_ROGUE:
1290 switch(m_spellInfo->Id )
1292 case 31231: // Cheat Death
1294 m_caster->CastSpell(m_caster,45182,true);
1295 return;
1297 case 5938: // Shiv
1299 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1300 return;
1302 Player *pCaster = ((Player*)m_caster);
1304 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1305 if(!item)
1306 return;
1308 // all poison enchantments is temporary
1309 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1310 if(!enchant_id)
1311 return;
1313 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1314 if(!pEnchant)
1315 return;
1317 for (int s=0;s<3;s++)
1319 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1320 continue;
1322 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1323 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1324 continue;
1326 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1329 m_caster->CastSpell(unitTarget, 5940, true);
1330 return;
1333 break;
1334 case SPELLFAMILY_HUNTER:
1335 // Steady Shot
1336 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1338 if( !unitTarget || !unitTarget->isAlive())
1339 return;
1341 bool found = false;
1343 // check dazed affect
1344 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1345 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1347 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1349 found = true;
1350 break;
1354 if(found)
1355 m_damage+= damage;
1356 return;
1358 // Kill command
1359 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1361 if(m_caster->getClass()!=CLASS_HUNTER)
1362 return;
1364 // clear hunter crit aura state
1365 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1367 // additional damage from pet to pet target
1368 Pet* pet = m_caster->GetPet();
1369 if(!pet || !pet->getVictim())
1370 return;
1372 uint32 spell_id = 0;
1373 switch (m_spellInfo->Id)
1375 case 34026: spell_id = 34027; break; // rank 1
1376 default:
1377 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1378 return;
1381 pet->CastSpell(pet->getVictim(), spell_id, true);
1382 return;
1385 switch(m_spellInfo->Id)
1387 case 23989: //Readiness talent
1389 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1390 return;
1392 //immediately finishes the cooldown for hunter abilities
1393 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1394 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1396 uint32 classspell = itr->first;
1397 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1399 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1401 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1403 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1404 data << uint32(classspell);
1405 data << uint64(m_caster->GetGUID());
1406 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1409 return;
1411 case 37506: // Scatter Shot
1413 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1414 return;
1416 // break Auto Shot and autohit
1417 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1418 m_caster->AttackStop();
1419 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1420 return;
1423 break;
1424 case SPELLFAMILY_PALADIN:
1425 switch(m_spellInfo->SpellIconID)
1427 case 156: // Holy Shock
1429 if(!unitTarget)
1430 return;
1432 int hurt = 0;
1433 int heal = 0;
1435 switch(m_spellInfo->Id)
1437 case 20473: hurt = 25912; heal = 25914; break;
1438 case 20929: hurt = 25911; heal = 25913; break;
1439 case 20930: hurt = 25902; heal = 25903; break;
1440 case 27174: hurt = 27176; heal = 27175; break;
1441 case 33072: hurt = 33073; heal = 33074; break;
1442 default:
1443 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1444 return;
1447 if(m_caster->IsFriendlyTo(unitTarget))
1448 m_caster->CastSpell(unitTarget, heal, true, 0);
1449 else
1450 m_caster->CastSpell(unitTarget, hurt, true, 0);
1452 return;
1454 case 561: // Judgement of command
1456 if(!unitTarget)
1457 return;
1459 uint32 spell_id = m_currentBasePoints[i]+1;
1460 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1461 if(!spell_proto)
1462 return;
1464 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1466 // decreased damage (/2) for non-stunned target.
1467 SpellModifier *mod = new SpellModifier;
1468 mod->op = SPELLMOD_DAMAGE;
1469 mod->value = -50;
1470 mod->type = SPELLMOD_PCT;
1471 mod->spellId = m_spellInfo->Id;
1472 mod->effectId = i;
1473 mod->lastAffected = NULL;
1474 mod->mask = 0x0000020000000000LL;
1475 mod->charges = 0;
1477 ((Player*)m_caster)->AddSpellMod(mod, true);
1478 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1479 // mod deleted
1480 ((Player*)m_caster)->AddSpellMod(mod, false);
1482 else
1483 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1485 return;
1489 switch(m_spellInfo->Id)
1491 case 31789: // Righteous Defense (step 1)
1493 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1495 // non-standard cast requirement check
1496 if (!unitTarget || unitTarget->getAttackers().empty())
1498 // clear cooldown at fail
1499 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1501 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1503 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1504 data << uint32(m_spellInfo->Id);
1505 data << uint64(m_caster->GetGUID());
1506 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1509 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1510 return;
1513 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1514 // Clear targets for eff 1
1515 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1516 ihit->effectMask &= ~(1<<1);
1518 // not empty (checked)
1519 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1521 // chance to be selected from list
1522 float chance = 100.0f/attackers.size();
1523 uint32 count=0;
1524 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1526 if(!roll_chance_f(chance))
1527 continue;
1528 ++count;
1529 AddUnitTarget((*aItr), 1);
1532 // now let next effect cast spell at each target.
1533 return;
1535 case 37877: // Blessing of Faith
1537 if(!unitTarget)
1538 return;
1540 uint32 spell_id = 0;
1541 switch(unitTarget->getClass())
1543 case CLASS_DRUID: spell_id = 37878; break;
1544 case CLASS_PALADIN: spell_id = 37879; break;
1545 case CLASS_PRIEST: spell_id = 37880; break;
1546 case CLASS_SHAMAN: spell_id = 37881; break;
1547 default: return; // ignore for not healing classes
1550 m_caster->CastSpell(m_caster,spell_id,true);
1551 return;
1554 break;
1555 case SPELLFAMILY_SHAMAN:
1556 //Shaman Rockbiter Weapon
1557 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1559 uint32 spell_id = 0;
1560 switch(m_spellInfo->Id)
1562 case 8017: spell_id = 36494; break; // Rank 1
1563 case 8018: spell_id = 36750; break; // Rank 2
1564 case 8019: spell_id = 36755; break; // Rank 3
1565 case 10399: spell_id = 36759; break; // Rank 4
1566 case 16314: spell_id = 36763; break; // Rank 5
1567 case 16315: spell_id = 36766; break; // Rank 6
1568 case 16316: spell_id = 36771; break; // Rank 7
1569 case 25479: spell_id = 36775; break; // Rank 8
1570 case 25485: spell_id = 36499; break; // Rank 9
1571 default:
1572 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1573 return;
1576 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1578 if(!spellInfo)
1580 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1581 return;
1584 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1585 return;
1587 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1589 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1591 if(item->IsFitToSpellRequirements(m_spellInfo))
1593 Spell *spell = new Spell(m_caster, spellInfo, true);
1595 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1596 // at calculation applied affect from Elemental Weapons talent
1597 // real enchantment damage-1
1598 spell->m_currentBasePoints[1] = damage-1;
1600 SpellCastTargets targets;
1601 targets.setItemTarget( item );
1602 spell->prepare(&targets);
1606 return;
1609 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1611 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1612 return;
1614 // Regenerate 6% of Total Mana Every 3 secs
1615 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1616 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1617 return;
1620 break;
1623 // pet auras
1624 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1626 m_caster->AddPetAura(petSpell);
1627 return;
1631 void Spell::EffectTriggerSpellWithValue(uint32 i)
1633 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1635 // normal case
1636 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1638 if(!spellInfo)
1640 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1641 return;
1644 int32 bp = damage;
1645 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1648 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1650 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1651 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1653 if(!spellInfo)
1655 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1656 return;
1659 finish();
1660 Spell *spell = new Spell(m_caster, spellInfo, true);
1662 SpellCastTargets targets;
1663 targets.setUnitTarget( unitTarget);
1664 spell->prepare(&targets);
1666 m_caster->SetCurrentCastedSpell(spell);
1667 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1671 void Spell::EffectForceCast(uint32 i)
1673 if( !unitTarget )
1674 return;
1676 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1678 // normal case
1679 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1681 if(!spellInfo)
1683 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1684 return;
1687 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1690 void Spell::EffectTriggerSpell(uint32 i)
1692 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1694 // special cases
1695 switch(triggered_spell_id)
1697 // Vanish
1698 case 18461:
1700 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1701 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1702 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1704 // if this spell is given to NPC it must handle rest by it's own AI
1705 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1706 return;
1708 // get highest rank of the Stealth spell
1709 uint32 spellId = 0;
1710 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1711 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1713 // only highest rank is shown in spell book, so simply check if shown in spell book
1714 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1715 continue;
1717 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1718 if (!spellInfo)
1719 continue;
1721 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1723 spellId = spellInfo->Id;
1724 break;
1728 // no Stealth spell found
1729 if (!spellId)
1730 return;
1732 // reset cooldown on it if needed
1733 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1734 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1736 m_caster->CastSpell(m_caster, spellId, true);
1737 return;
1739 // just skip
1740 case 23770: // Sayge's Dark Fortune of *
1741 // not exist, common cooldown can be implemented in scripts if need.
1742 return;
1743 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1744 case 29284:
1746 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1747 if (!spell)
1748 return;
1750 for (int i=0; i < spell->StackAmount; ++i)
1751 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1752 return;
1754 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1755 case 29286:
1757 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1758 if (!spell)
1759 return;
1761 for (int i=0; i < spell->StackAmount; ++i)
1762 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1763 return;
1765 // Righteous Defense
1766 case 31980:
1768 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1769 return;
1771 // Cloak of Shadows
1772 case 35729 :
1774 Unit::AuraMap& Auras = m_caster->GetAuras();
1775 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1777 // remove all harmful spells on you...
1778 if( // ignore positive and passive auras
1779 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1780 // ignore physical auras
1781 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1782 // ignore immunity persistent spells
1783 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1785 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1786 iter = Auras.begin();
1789 return;
1791 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1792 case 41967:
1794 if (Unit *pet = m_caster->GetPet())
1795 pet->CastSpell(pet, 28305, true);
1796 return;
1800 // normal case
1801 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1803 if(!spellInfo)
1805 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1806 return;
1809 // some triggered spells require specific equipment
1810 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1812 // main hand weapon required
1813 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1815 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1817 // skip spell if no weapon in slot or broken
1818 if(!item || item->IsBroken() )
1819 return;
1821 // skip spell if weapon not fit to triggered spell
1822 if(!item->IsFitToSpellRequirements(spellInfo))
1823 return;
1826 // offhand hand weapon required
1827 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1829 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1831 // skip spell if no weapon in slot or broken
1832 if(!item || item->IsBroken() )
1833 return;
1835 // skip spell if weapon not fit to triggered spell
1836 if(!item->IsFitToSpellRequirements(spellInfo))
1837 return;
1841 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1842 bool instant = false;
1843 for(uint32 j = i+1; j < 3; ++j)
1845 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1847 instant = true;
1848 break;
1852 if(instant)
1854 if (unitTarget)
1855 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1857 else
1858 m_TriggerSpells.push_back(spellInfo);
1861 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1863 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1865 // normal case
1866 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1868 if(!spellInfo)
1870 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1871 m_spellInfo->Id,effect_idx,triggered_spell_id);
1872 return;
1875 if (m_CastItem)
1876 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1878 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1880 SpellCastTargets targets;
1881 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1882 spell->m_CastItem = m_CastItem;
1883 spell->prepare(&targets, NULL);
1886 void Spell::EffectTeleportUnits(uint32 i)
1888 if(!unitTarget || unitTarget->isInFlight())
1889 return;
1891 switch (m_spellInfo->EffectImplicitTargetB[i])
1893 case TARGET_INNKEEPER_COORDINATES:
1895 // Only players can teleport to innkeeper
1896 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1897 return;
1899 ((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);
1900 return;
1902 case TARGET_TABLE_X_Y_Z_COORDINATES:
1904 // TODO: Only players can teleport?
1905 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1906 return;
1907 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1908 if(!st)
1910 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1911 return;
1913 ((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);
1914 break;
1916 case TARGET_BEHIND_VICTIM:
1918 // Get selected target for player (or victim for units)
1919 Unit *pTarget = NULL;
1920 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1921 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1922 else
1923 pTarget = m_caster->getVictim();
1924 // No target present - return
1925 if (!pTarget)
1926 return;
1927 // Init dest coordinates
1928 uint32 mapid = m_caster->GetMapId();
1929 float x = m_targets.m_destX;
1930 float y = m_targets.m_destY;
1931 float z = m_targets.m_destZ;
1932 float orientation = pTarget->GetOrientation();
1933 // Teleport
1934 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1935 ((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));
1936 else
1938 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1939 WorldPacket data;
1940 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1941 unitTarget->SendMessageToSet(&data, false);
1943 return;
1945 default:
1947 // If not exist data for dest location - return
1948 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
1950 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
1951 return;
1953 // Init dest coordinates
1954 uint32 mapid = m_caster->GetMapId();
1955 float x = m_targets.m_destX;
1956 float y = m_targets.m_destY;
1957 float z = m_targets.m_destZ;
1958 float orientation = unitTarget->GetOrientation();
1959 // Teleport
1960 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1961 ((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));
1962 else
1964 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1965 WorldPacket data;
1966 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1967 unitTarget->SendMessageToSet(&data, false);
1969 return;
1973 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1974 switch ( m_spellInfo->Id )
1976 // Dimensional Ripper - Everlook
1977 case 23442:
1979 int32 r = irand(0, 119);
1980 if ( r >= 70 ) // 7/12 success
1982 if ( r < 100 ) // 4/12 evil twin
1983 m_caster->CastSpell(m_caster,23445,true);
1984 else // 1/12 fire
1985 m_caster->CastSpell(m_caster,23449,true);
1987 return;
1989 // Ultrasafe Transporter: Toshley's Station
1990 case 36941:
1992 if ( roll_chance_i(50) ) // 50% success
1994 int32 rand_eff = urand(1,7);
1995 switch ( rand_eff )
1997 case 1:
1998 // soul split - evil
1999 m_caster->CastSpell(m_caster,36900,true);
2000 break;
2001 case 2:
2002 // soul split - good
2003 m_caster->CastSpell(m_caster,36901,true);
2004 break;
2005 case 3:
2006 // Increase the size
2007 m_caster->CastSpell(m_caster,36895,true);
2008 break;
2009 case 4:
2010 // Decrease the size
2011 m_caster->CastSpell(m_caster,36893,true);
2012 break;
2013 case 5:
2014 // Transform
2016 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2017 m_caster->CastSpell(m_caster,36897,true);
2018 else
2019 m_caster->CastSpell(m_caster,36899,true);
2020 break;
2022 case 6:
2023 // chicken
2024 m_caster->CastSpell(m_caster,36940,true);
2025 break;
2026 case 7:
2027 // evil twin
2028 m_caster->CastSpell(m_caster,23445,true);
2029 break;
2032 return;
2034 // Dimensional Ripper - Area 52
2035 case 36890:
2037 if ( roll_chance_i(50) ) // 50% success
2039 int32 rand_eff = urand(1,4);
2040 switch ( rand_eff )
2042 case 1:
2043 // soul split - evil
2044 m_caster->CastSpell(m_caster,36900,true);
2045 break;
2046 case 2:
2047 // soul split - good
2048 m_caster->CastSpell(m_caster,36901,true);
2049 break;
2050 case 3:
2051 // Increase the size
2052 m_caster->CastSpell(m_caster,36895,true);
2053 break;
2054 case 4:
2055 // Transform
2057 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2058 m_caster->CastSpell(m_caster,36897,true);
2059 else
2060 m_caster->CastSpell(m_caster,36899,true);
2061 break;
2065 return;
2070 void Spell::EffectApplyAura(uint32 i)
2072 if(!unitTarget)
2073 return;
2075 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2076 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2077 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2078 return;
2080 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2081 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2082 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2083 return;
2085 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2086 if(!caster)
2087 return;
2089 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2091 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2093 // Now Reduce spell duration using data received at spell hit
2094 int32 duration = Aur->GetAuraMaxDuration();
2095 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2096 Aur->setDiminishGroup(m_diminishGroup);
2098 // if Aura removed and deleted, do not continue.
2099 if(duration== 0 && !(Aur->IsPermanent()))
2101 delete Aur;
2102 return;
2105 if(duration != Aur->GetAuraMaxDuration())
2107 Aur->SetAuraMaxDuration(duration);
2108 Aur->SetAuraDuration(duration);
2111 bool added = unitTarget->AddAura(Aur);
2113 // Aura not added and deleted in AddAura call;
2114 if (!added)
2115 return;
2117 // found crash at character loading, broken pointer to Aur...
2118 // Aur was deleted in AddAura()...
2119 if(!Aur)
2120 return;
2122 // TODO Make a way so it works for every related spell!
2123 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2125 uint32 spellId = 0;
2126 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2127 spellId = 6788; // Weakened Soul
2128 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2129 spellId = 25771; // Forbearance
2130 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2131 spellId = 41425; // Hypothermia
2132 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2133 spellId = 11196; // Recently Bandaged
2134 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2135 spellId = 23230; // Blood Fury - Healing Reduction
2137 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2138 if (AdditionalSpellInfo)
2140 // applied at target by target
2141 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2142 unitTarget->AddAura(AdditionalAura);
2143 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2147 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2148 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2149 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2152 void Spell::EffectUnlearnSpecialization( uint32 i )
2154 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2155 return;
2157 Player *_player = (Player*)unitTarget;
2158 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2160 _player->removeSpell(spellToUnlearn);
2162 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2165 void Spell::EffectPowerDrain(uint32 i)
2167 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2168 return;
2170 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2172 if(!unitTarget)
2173 return;
2174 if(!unitTarget->isAlive())
2175 return;
2176 if(unitTarget->getPowerType() != drain_power)
2177 return;
2178 if(damage < 0)
2179 return;
2181 uint32 curPower = unitTarget->GetPower(drain_power);
2183 //add spell damage bonus
2184 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2186 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2187 uint32 power = damage;
2188 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2189 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2191 int32 new_damage;
2192 if(curPower < power)
2193 new_damage = curPower;
2194 else
2195 new_damage = power;
2197 unitTarget->ModifyPower(drain_power,-new_damage);
2199 if(drain_power == POWER_MANA)
2201 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2202 if(manaMultiplier==0)
2203 manaMultiplier = 1;
2205 if(Player *modOwner = m_caster->GetSpellModOwner())
2206 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2208 int32 gain = int32(new_damage*manaMultiplier);
2210 m_caster->ModifyPower(POWER_MANA,gain);
2211 //send log
2212 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2216 void Spell::EffectSendEvent(uint32 EffectIndex)
2218 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2220 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2221 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2223 switch(m_spellInfo->Id)
2225 case 23333: // Pickup Horde Flag
2226 /*do not uncomment .
2227 if(bg->GetTypeID()==BATTLEGROUND_WS)
2228 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2229 sLog.outDebug("Send Event Horde Flag Picked Up");
2230 break;
2231 /* not used :
2232 case 23334: // Drop Horde Flag
2233 if(bg->GetTypeID()==BATTLEGROUND_WS)
2234 bg->EventPlayerDroppedFlag((Player*)m_caster);
2235 sLog.outDebug("Drop Horde Flag");
2236 break;
2238 case 23335: // Pickup Alliance Flag
2239 /*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
2240 if(bg->GetTypeID()==BATTLEGROUND_WS)
2241 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2242 sLog.outDebug("Send Event Alliance Flag Picked Up");
2243 break;
2244 /* not used :
2245 case 23336: // Drop Alliance Flag
2246 if(bg->GetTypeID()==BATTLEGROUND_WS)
2247 bg->EventPlayerDroppedFlag((Player*)m_caster);
2248 sLog.outDebug("Drop Alliance Flag");
2249 break;
2250 case 23385: // Alliance Flag Returns
2251 if(bg->GetTypeID()==BATTLEGROUND_WS)
2252 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2253 sLog.outDebug("Alliance Flag Returned");
2254 break;
2255 case 23386: // Horde Flag Returns
2256 if(bg->GetTypeID()==BATTLEGROUND_WS)
2257 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2258 sLog.outDebug("Horde Flag Returned");
2259 break;*/
2260 case 34976:
2262 if(bg->GetTypeID()==BATTLEGROUND_EY)
2263 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2265 break;
2266 default:
2267 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2268 break;
2272 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2273 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2276 void Spell::EffectPowerBurn(uint32 i)
2278 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2279 return;
2281 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2283 if(!unitTarget)
2284 return;
2285 if(!unitTarget->isAlive())
2286 return;
2287 if(unitTarget->getPowerType()!=powertype)
2288 return;
2289 if(damage < 0)
2290 return;
2292 int32 curPower = int32(unitTarget->GetPower(powertype));
2294 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2295 uint32 power = damage;
2296 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2297 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2299 int32 new_damage = (curPower < power) ? curPower : power;
2301 unitTarget->ModifyPower(powertype,-new_damage);
2302 float multiplier = m_spellInfo->EffectMultipleValue[i];
2304 if(Player *modOwner = m_caster->GetSpellModOwner())
2305 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2307 new_damage = int32(new_damage*multiplier);
2308 m_damage+=new_damage;
2311 void Spell::EffectHeal( uint32 /*i*/ )
2313 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2315 // Try to get original caster
2316 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2318 // Skip if m_originalCaster not available
2319 if (!caster)
2320 return;
2322 int32 addhealth = damage;
2324 // Vessel of the Naaru (Vial of the Sunwell trinket)
2325 if (m_spellInfo->Id == 45064)
2327 // Amount of heal - depends from stacked Holy Energy
2328 int damageAmount = 0;
2329 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2330 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2331 if((*i)->GetId() == 45062)
2332 damageAmount+=(*i)->GetModifier()->m_amount;
2333 if (damageAmount)
2334 m_caster->RemoveAurasDueToSpell(45062);
2336 addhealth += damageAmount;
2338 // Swiftmend - consumes Regrowth or Rejuvenation
2339 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2341 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2342 // find most short by duration
2343 Aura *targetAura = NULL;
2344 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2346 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2347 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2349 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2350 targetAura = *i;
2354 if(!targetAura)
2356 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2357 return;
2359 int idx = 0;
2360 while(idx < 3)
2362 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2363 break;
2364 idx++;
2367 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2368 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2369 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2371 addhealth += tickheal * tickcount;
2373 else
2374 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2376 m_healing+=addhealth;
2380 void Spell::EffectHealPct( uint32 /*i*/ )
2382 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2384 // Try to get original caster
2385 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2387 // Skip if m_originalCaster not available
2388 if (!caster)
2389 return;
2391 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2392 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2394 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2395 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2397 if(caster->GetTypeId()==TYPEID_PLAYER)
2398 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2399 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2403 void Spell::EffectHealMechanical( uint32 /*i*/ )
2405 // Mechanic creature type should be correctly checked by targetCreatureType field
2406 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2408 // Try to get original caster
2409 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2411 // Skip if m_originalCaster not available
2412 if (!caster)
2413 return;
2415 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2416 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2417 unitTarget->ModifyHealth( int32(damage) );
2421 void Spell::EffectHealthLeech(uint32 i)
2423 if(!unitTarget)
2424 return;
2425 if(!unitTarget->isAlive())
2426 return;
2428 if(damage < 0)
2429 return;
2431 sLog.outDebug("HealthLeech :%i", damage);
2433 float multiplier = m_spellInfo->EffectMultipleValue[i];
2435 if(Player *modOwner = m_caster->GetSpellModOwner())
2436 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2438 int32 new_damage = int32(damage*multiplier);
2439 uint32 curHealth = unitTarget->GetHealth();
2440 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2441 if(curHealth < new_damage)
2442 new_damage = curHealth;
2444 if(m_caster->isAlive())
2446 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2448 m_caster->ModifyHealth(new_damage);
2450 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2451 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2453 // m_healthLeech+=tmpvalue;
2454 // m_damage+=new_damage;
2457 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2459 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2460 return;
2462 Player* player = (Player*)unitTarget;
2464 uint32 newitemid = itemtype;
2465 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2466 if(!pProto)
2468 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2469 return;
2472 uint32 num_to_add;
2474 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2475 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2477 int32 basePoints = m_currentBasePoints[i];
2478 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2479 if (randomPoints)
2480 num_to_add = basePoints + irand(1, randomPoints);
2481 else
2482 num_to_add = basePoints + 1;
2484 else if (pProto->MaxCount == 1)
2485 num_to_add = 1;
2486 else if(player->getLevel() >= m_spellInfo->spellLevel)
2488 int32 basePoints = m_currentBasePoints[i];
2489 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2490 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2492 else
2493 num_to_add = 2;
2495 if (num_to_add < 1)
2496 num_to_add = 1;
2497 if (num_to_add > pProto->Stackable)
2498 num_to_add = pProto->Stackable;
2500 // init items_count to 1, since 1 item will be created regardless of specialization
2501 int items_count=1;
2502 // the chance to create additional items
2503 float additionalCreateChance=0.0f;
2504 // the maximum number of created additional items
2505 uint8 additionalMaxNum=0;
2506 // get the chance and maximum number for creating extra items
2507 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2509 // roll with this chance till we roll not to create or we create the max num
2510 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2511 ++items_count;
2514 // really will be created more items
2515 num_to_add *= items_count;
2517 // can the player store the new item?
2518 ItemPosCountVec dest;
2519 uint32 no_space = 0;
2520 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2521 if( msg != EQUIP_ERR_OK )
2523 // convert to possible store amount
2524 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2525 num_to_add -= no_space;
2526 else
2528 // if not created by another reason from full inventory or unique items amount limitation
2529 player->SendEquipError( msg, NULL, NULL );
2530 return;
2534 if(num_to_add)
2536 // create the new item and store it
2537 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2539 // was it successful? return error if not
2540 if(!pItem)
2542 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2543 return;
2546 // set the "Crafted by ..." property of the item
2547 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2548 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2550 // send info to the client
2551 if(pItem)
2552 player->SendNewItem(pItem, num_to_add, true, true);
2554 // we succeeded in creating at least one item, so a levelup is possible
2555 player->UpdateCraftSkill(m_spellInfo->Id);
2558 // for battleground marks send by mail if not add all expected
2559 if(no_space > 0 )
2561 BattleGroundTypeId bgType;
2562 switch(m_spellInfo->Id)
2564 case SPELL_AV_MARK_WINNER:
2565 case SPELL_AV_MARK_LOSER:
2566 bgType = BATTLEGROUND_AV;
2567 break;
2568 case SPELL_WS_MARK_WINNER:
2569 case SPELL_WS_MARK_LOSER:
2570 bgType = BATTLEGROUND_WS;
2571 break;
2572 case SPELL_AB_MARK_WINNER:
2573 case SPELL_AB_MARK_LOSER:
2574 bgType = BATTLEGROUND_AB;
2575 break;
2576 default:
2577 return;
2580 if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
2581 bg->SendRewardMarkByMail(player,newitemid,no_space);
2585 void Spell::EffectCreateItem(uint32 i)
2587 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2590 void Spell::EffectPersistentAA(uint32 i)
2592 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2594 if(Player* modOwner = m_caster->GetSpellModOwner())
2595 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2597 int32 duration = GetSpellDuration(m_spellInfo);
2598 DynamicObject* dynObj = new DynamicObject;
2599 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))
2601 delete dynObj;
2602 return;
2604 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2605 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2606 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2607 m_caster->AddDynObject(dynObj);
2608 dynObj->GetMap()->Add(dynObj);
2611 void Spell::EffectEnergize(uint32 i)
2613 if(!unitTarget)
2614 return;
2615 if(!unitTarget->isAlive())
2616 return;
2618 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2619 return;
2621 // Some level depends spells
2622 int multiplier = 0;
2623 int level_diff = 0;
2624 switch (m_spellInfo->Id)
2626 // Restore Energy
2627 case 9512:
2628 level_diff = m_caster->getLevel() - 40;
2629 multiplier = 2;
2630 break;
2631 // Blood Fury
2632 case 24571:
2633 level_diff = m_caster->getLevel() - 60;
2634 multiplier = 10;
2635 break;
2636 // Burst of Energy
2637 case 24532:
2638 level_diff = m_caster->getLevel() - 60;
2639 multiplier = 4;
2640 break;
2641 default:
2642 break;
2645 if (level_diff > 0)
2646 damage -= multiplier * level_diff;
2648 if(damage < 0)
2649 return;
2651 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2653 if(unitTarget->GetMaxPower(power) == 0)
2654 return;
2656 unitTarget->ModifyPower(power,damage);
2657 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2659 // Mad Alchemist's Potion
2660 if (m_spellInfo->Id == 45051)
2662 // find elixirs on target
2663 uint32 elixir_mask = 0;
2664 Unit::AuraMap& Auras = unitTarget->GetAuras();
2665 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2667 uint32 spell_id = itr->second->GetId();
2668 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2669 elixir_mask |= mask;
2672 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2673 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2675 // get all available elixirs by mask and spell level
2676 std::vector<uint32> elixirs;
2677 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2678 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2680 if (itr->second & elixir_mask)
2682 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2683 continue;
2685 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2686 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2687 continue;
2689 elixirs.push_back(itr->first);
2693 if (!elixirs.empty())
2695 // cast random elixir on target
2696 uint32 rand_spell = urand(0,elixirs.size()-1);
2697 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2702 void Spell::EffectEnergisePct(uint32 i)
2704 if(!unitTarget)
2705 return;
2706 if(!unitTarget->isAlive())
2707 return;
2709 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2710 return;
2712 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2714 uint32 maxPower = unitTarget->GetMaxPower(power);
2715 if(maxPower == 0)
2716 return;
2718 uint32 gain = damage * maxPower / 100;
2719 unitTarget->ModifyPower(power, gain);
2720 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2723 void Spell::SendLoot(uint64 guid, LootType loottype)
2725 Player* player = (Player*)m_caster;
2726 if (!player)
2727 return;
2729 if (gameObjTarget)
2731 if (Script->GOHello(player, gameObjTarget))
2732 return;
2734 switch (gameObjTarget->GetGoType())
2736 case GAMEOBJECT_TYPE_DOOR:
2737 case GAMEOBJECT_TYPE_BUTTON:
2738 gameObjTarget->UseDoorOrButton();
2739 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2740 return;
2742 case GAMEOBJECT_TYPE_QUESTGIVER:
2743 // start or end quest
2744 player->PrepareQuestMenu(guid);
2745 player->SendPreparedQuest(guid);
2746 return;
2748 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2749 // triggering linked GO
2750 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2751 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2752 return;
2754 case GAMEOBJECT_TYPE_GOOBER:
2755 // goober_scripts can be triggered if the player don't have the quest
2756 if (gameObjTarget->GetGOInfo()->goober.eventId)
2758 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2759 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2762 // cast goober spell
2763 if (gameObjTarget->GetGOInfo()->goober.questId)
2764 ///Quest require to be active for GO using
2765 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2766 return;
2768 gameObjTarget->AddUniqueUse(player);
2769 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2771 //TODO? Objective counting called without spell check but with quest objective check
2772 // if send spell id then this line will duplicate to spell casting call (double counting)
2773 // So we or have this line and not required in quest_template have reqSpellIdN
2774 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2775 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2777 // triggering linked GO
2778 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2779 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2781 return;
2783 case GAMEOBJECT_TYPE_CHEST:
2784 // TODO: possible must be moved to loot release (in different from linked triggering)
2785 if (gameObjTarget->GetGOInfo()->chest.eventId)
2787 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2788 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2791 // triggering linked GO
2792 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2793 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2795 // Don't return, let loots been taken
2799 // Send loot
2800 player->SendLoot(guid, loottype);
2803 void Spell::EffectOpenLock(uint32 /*i*/)
2805 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2807 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2808 return;
2811 Player* player = (Player*)m_caster;
2813 LootType loottype = LOOT_CORPSE;
2814 uint32 lockId = 0;
2815 uint64 guid = 0;
2817 // Get lockId
2818 if(gameObjTarget)
2820 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2821 // Arathi Basin banner opening !
2822 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2823 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2825 //isAllowUseBattleGroundObject() already called in CanCast()
2826 // in battleground check
2827 if(BattleGround *bg = player->GetBattleGround())
2829 // check if it's correct bg
2830 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2831 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2832 return;
2835 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2837 //isAllowUseBattleGroundObject() already called in CanCast()
2838 // in battleground check
2839 if(BattleGround *bg = player->GetBattleGround())
2841 if(bg->GetTypeID() == BATTLEGROUND_EY)
2842 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2843 return;
2846 lockId = gameObjTarget->GetLockId();
2847 guid = gameObjTarget->GetGUID();
2849 else if(itemTarget)
2851 lockId = itemTarget->GetProto()->LockID;
2852 guid = itemTarget->GetGUID();
2854 else
2856 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2857 return;
2860 if(!lockId) // possible case for GO and maybe for items.
2862 SendLoot(guid, loottype);
2863 return;
2866 // Get LockInfo
2867 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2869 if (!lockInfo)
2871 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2872 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2873 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2874 return;
2877 // check key
2878 for(int i = 0; i < 5; ++i)
2880 // type==1 This means lockInfo->key[i] is an item
2881 if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i])
2883 SendLoot(guid, loottype);
2884 return;
2888 uint32 SkillId = 0;
2889 // Check and skill-up skill
2890 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2891 SkillId = m_spellInfo->EffectMiscValue[1];
2892 // pickpocketing spells
2893 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2894 SkillId = SKILL_LOCKPICKING;
2896 // skill bonus provided by casting spell (mostly item spells)
2897 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2899 uint32 reqSkillValue = lockInfo->requiredminingskill;
2901 if(lockInfo->requiredlockskill) // required pick lock skill applying
2903 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2905 SendCastResult(SPELL_FAILED_FIZZLE);
2906 return;
2909 reqSkillValue = lockInfo->requiredlockskill;
2911 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2913 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2914 return;
2917 if ( SkillId )
2919 loottype = LOOT_SKINNING;
2920 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2922 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2923 return;
2926 // update skill if really known
2927 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2928 if(SkillValue) // non only item base skill
2930 if(gameObjTarget)
2932 // Allow one skill-up until respawned
2933 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
2934 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
2935 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
2937 else if(itemTarget)
2939 // Do one skill-up
2940 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2941 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
2946 SendLoot(guid, loottype);
2949 void Spell::EffectSummonChangeItem(uint32 i)
2951 if(m_caster->GetTypeId() != TYPEID_PLAYER)
2952 return;
2954 Player *player = (Player*)m_caster;
2956 // applied only to using item
2957 if(!m_CastItem)
2958 return;
2960 // ... only to item in own inventory/bank/equip_slot
2961 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
2962 return;
2964 uint32 newitemid = m_spellInfo->EffectItemType[i];
2965 if(!newitemid)
2966 return;
2968 uint16 pos = m_CastItem->GetPos();
2970 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
2971 if( !pNewItem )
2972 return;
2974 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
2976 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
2977 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
2980 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
2982 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
2983 player->DurabilityLoss(pNewItem, loosePercent);
2986 if( player->IsInventoryPos( pos ) )
2988 ItemPosCountVec dest;
2989 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
2990 if( msg == EQUIP_ERR_OK )
2992 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
2994 // prevent crash at access and unexpected charges counting with item update queue corrupt
2995 if(m_CastItem==m_targets.getItemTarget())
2996 m_targets.setItemTarget(NULL);
2998 m_CastItem = NULL;
3000 player->StoreItem( dest, pNewItem, true);
3001 return;
3004 else if( player->IsBankPos ( pos ) )
3006 ItemPosCountVec dest;
3007 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3008 if( msg == EQUIP_ERR_OK )
3010 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3012 // prevent crash at access and unexpected charges counting with item update queue corrupt
3013 if(m_CastItem==m_targets.getItemTarget())
3014 m_targets.setItemTarget(NULL);
3016 m_CastItem = NULL;
3018 player->BankItem( dest, pNewItem, true);
3019 return;
3022 else if( player->IsEquipmentPos ( pos ) )
3024 uint16 dest;
3025 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3026 if( msg == EQUIP_ERR_OK )
3028 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3030 // prevent crash at access and unexpected charges counting with item update queue corrupt
3031 if(m_CastItem==m_targets.getItemTarget())
3032 m_targets.setItemTarget(NULL);
3034 m_CastItem = NULL;
3036 player->EquipItem( dest, pNewItem, true);
3037 player->AutoUnequipOffhandIfNeed();
3038 return;
3042 // fail
3043 delete pNewItem;
3046 void Spell::EffectOpenSecretSafe(uint32 i)
3048 EffectOpenLock(i); //no difference for now
3051 void Spell::EffectProficiency(uint32 /*i*/)
3053 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3054 return;
3055 Player *p_target = (Player*)unitTarget;
3057 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3058 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3060 p_target->AddWeaponProficiency(subClassMask);
3061 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3063 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3065 p_target->AddArmorProficiency(subClassMask);
3066 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3070 void Spell::EffectApplyAreaAura(uint32 i)
3072 if(!unitTarget)
3073 return;
3074 if(!unitTarget->isAlive())
3075 return;
3077 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3078 unitTarget->AddAura(Aur);
3081 void Spell::EffectSummonType(uint32 i)
3083 switch(m_spellInfo->EffectMiscValueB[i])
3085 case SUMMON_TYPE_GUARDIAN:
3086 case SUMMON_TYPE_POSESSED:
3087 case SUMMON_TYPE_POSESSED2:
3088 EffectSummonGuardian(i);
3089 break;
3090 case SUMMON_TYPE_WILD:
3091 EffectSummonWild(i);
3092 break;
3093 case SUMMON_TYPE_DEMON:
3094 EffectSummonDemon(i);
3095 break;
3096 case SUMMON_TYPE_SUMMON:
3097 EffectSummon(i);
3098 break;
3099 case SUMMON_TYPE_CRITTER:
3100 case SUMMON_TYPE_CRITTER2:
3101 case SUMMON_TYPE_CRITTER3:
3102 EffectSummonCritter(i);
3103 break;
3104 case SUMMON_TYPE_TOTEM_SLOT1:
3105 case SUMMON_TYPE_TOTEM_SLOT2:
3106 case SUMMON_TYPE_TOTEM_SLOT3:
3107 case SUMMON_TYPE_TOTEM_SLOT4:
3108 case SUMMON_TYPE_TOTEM:
3109 EffectSummonTotem(i);
3110 break;
3111 case SUMMON_TYPE_UNKNOWN1:
3112 case SUMMON_TYPE_UNKNOWN2:
3113 case SUMMON_TYPE_UNKNOWN3:
3114 case SUMMON_TYPE_UNKNOWN4:
3115 case SUMMON_TYPE_UNKNOWN5:
3116 break;
3117 default:
3118 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3119 break;
3123 void Spell::EffectSummon(uint32 i)
3125 if(m_caster->GetPetGUID())
3126 return;
3128 if(!unitTarget)
3129 return;
3130 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3131 if(!pet_entry)
3132 return;
3133 uint32 level = m_caster->getLevel();
3134 Pet* spawnCreature = new Pet(SUMMON_PET);
3136 if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
3138 // set timer for unsummon
3139 int32 duration = GetSpellDuration(m_spellInfo);
3140 if(duration > 0)
3141 spawnCreature->SetDuration(duration);
3143 return;
3146 Map *map = m_caster->GetMap();
3147 uint32 pet_number = objmgr.GeneratePetNumber();
3148 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3150 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3151 delete spawnCreature;
3152 return;
3155 // Summon in dest location
3156 float x,y,z;
3157 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3159 x = m_targets.m_destX;
3160 y = m_targets.m_destY;
3161 z = m_targets.m_destZ;
3163 else
3164 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3166 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3168 if(!spawnCreature->IsPositionValid())
3170 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3171 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3172 delete spawnCreature;
3173 return;
3176 // set timer for unsummon
3177 int32 duration = GetSpellDuration(m_spellInfo);
3178 if(duration > 0)
3179 spawnCreature->SetDuration(duration);
3181 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3182 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3183 spawnCreature->setPowerType(POWER_MANA);
3184 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3185 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3186 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3187 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3188 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3189 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3190 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3191 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3192 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3194 spawnCreature->InitStatsForLevel(level);
3196 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3198 spawnCreature->AIM_Initialize();
3199 spawnCreature->InitPetCreateSpells();
3200 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3201 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3203 std::string name = m_caster->GetName();
3204 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3205 spawnCreature->SetName( name );
3207 map->Add((Creature*)spawnCreature);
3209 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3211 m_caster->SetPet(spawnCreature);
3212 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3213 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3214 ((Player*)m_caster)->PetSpellInitialize();
3218 void Spell::EffectLearnSpell(uint32 i)
3220 if(!unitTarget)
3221 return;
3223 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3225 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3226 EffectLearnPetSpell(i);
3228 return;
3231 Player *player = (Player*)unitTarget;
3233 uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i];
3234 player->learnSpell(spellToLearn);
3236 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3239 void Spell::EffectDispel(uint32 i)
3241 if(!unitTarget)
3242 return;
3244 // Fill possible dispell list
3245 std::vector <Aura *> dispel_list;
3247 // Create dispel mask by dispel type
3248 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3249 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3250 Unit::AuraMap const& auras = unitTarget->GetAuras();
3251 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3253 Aura *aur = (*itr).second;
3254 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3256 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3258 bool positive = true;
3259 if (!aur->IsPositive())
3260 positive = false;
3261 else
3262 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3264 // do not remove positive auras if friendly target
3265 // negative auras if non-friendly target
3266 if(positive == unitTarget->IsFriendlyTo(m_caster))
3267 continue;
3269 // Add aura to dispel list
3270 dispel_list.push_back(aur);
3273 // Ok if exist some buffs for dispel try dispel it
3274 if (!dispel_list.empty())
3276 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3277 std::list < uint32 > fail_list; // spell_id
3278 int32 list_size = dispel_list.size();
3279 // Dispell N = damage buffs (or while exist buffs for dispel)
3280 for (int32 count=0; count < damage && list_size > 0; ++count)
3282 // Random select buff for dispel
3283 Aura *aur = dispel_list[urand(0, list_size-1)];
3285 SpellEntry const* spellInfo = aur->GetSpellProto();
3286 // Base dispel chance
3287 // TODO: possible chance depend from spell level??
3288 int32 miss_chance = 0;
3289 // Apply dispel mod from aura caster
3290 if (Unit *caster = aur->GetCaster())
3292 if ( Player* modOwner = caster->GetSpellModOwner() )
3293 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3295 // Try dispel
3296 if (roll_chance_i(miss_chance))
3297 fail_list.push_back(aur->GetId());
3298 else
3299 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3300 // Remove buff from list for prevent doubles
3301 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3303 Aura *dispeled = *j;
3304 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3306 j = dispel_list.erase(j);
3307 --list_size;
3309 else
3310 ++j;
3313 // Send success log and really remove auras
3314 if (!success_list.empty())
3316 int32 count = success_list.size();
3317 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3318 data.append(unitTarget->GetPackGUID()); // Victim GUID
3319 data.append(m_caster->GetPackGUID()); // Caster GUID
3320 data << uint32(m_spellInfo->Id); // Dispell spell id
3321 data << uint8(0); // not used
3322 data << uint32(count); // count
3323 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3325 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3326 data << uint32(spellInfo->Id); // Spell Id
3327 data << uint8(0); // 0 - dispeled !=0 cleansed
3328 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3330 m_caster->SendMessageToSet(&data, true);
3332 // On succes dispel
3333 // Devour Magic
3334 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3336 uint32 heal_spell = 0;
3337 switch (m_spellInfo->Id)
3339 case 19505: heal_spell = 19658; break;
3340 case 19731: heal_spell = 19732; break;
3341 case 19734: heal_spell = 19733; break;
3342 case 19736: heal_spell = 19735; break;
3343 case 27276: heal_spell = 27278; break;
3344 case 27277: heal_spell = 27279; break;
3345 default:
3346 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3347 break;
3349 if (heal_spell)
3350 m_caster->CastSpell(m_caster, heal_spell, true);
3353 // Send fail log to client
3354 if (!fail_list.empty())
3356 // Failed to dispell
3357 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3358 data << uint64(m_caster->GetGUID()); // Caster GUID
3359 data << uint64(unitTarget->GetGUID()); // Victim GUID
3360 data << uint32(m_spellInfo->Id); // Dispell spell id
3361 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3362 data << uint32(*j); // Spell Id
3363 m_caster->SendMessageToSet(&data, true);
3368 void Spell::EffectDualWield(uint32 /*i*/)
3370 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
3371 ((Player*)unitTarget)->SetCanDualWield(true);
3374 void Spell::EffectPull(uint32 /*i*/)
3376 // TODO: create a proper pull towards distract spell center for distract
3377 sLog.outDebug("WORLD: Spell Effect DUMMY");
3380 void Spell::EffectDistract(uint32 /*i*/)
3382 // Check for possible target
3383 if (!unitTarget || unitTarget->isInCombat())
3384 return;
3386 // target must be OK to do this
3387 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3388 return;
3390 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3392 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3394 // For players just turn them
3395 WorldPacket data;
3396 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3397 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3398 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3400 else
3402 // Set creature Distracted, Stop it, And turn it
3403 unitTarget->SetOrientation(angle);
3404 unitTarget->StopMoving();
3405 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3409 void Spell::EffectPickPocket(uint32 /*i*/)
3411 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3412 return;
3414 // victim must be creature and attackable
3415 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3416 return;
3418 // victim have to be alive and humanoid or undead
3419 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3421 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3423 if (chance > irand(0, 19))
3425 // Stealing successful
3426 //sLog.outDebug("Sending loot from pickpocket");
3427 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3429 else
3431 // Reveal action + get attack
3432 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3433 if (((Creature*)unitTarget)->AI())
3434 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3439 void Spell::EffectAddFarsight(uint32 i)
3441 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3442 int32 duration = GetSpellDuration(m_spellInfo);
3443 DynamicObject* dynObj = new DynamicObject;
3444 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))
3446 delete dynObj;
3447 return;
3449 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3450 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3451 m_caster->AddDynObject(dynObj);
3452 dynObj->GetMap()->Add(dynObj);
3453 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3454 ((Player*)m_caster)->SetFarSight(dynObj->GetGUID());
3457 void Spell::EffectSummonWild(uint32 i)
3459 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3460 if(!creature_entry)
3461 return;
3463 uint32 level = m_caster->getLevel();
3465 // level of creature summoned using engineering item based at engineering skill level
3466 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3468 ItemPrototype const *proto = m_CastItem->GetProto();
3469 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3471 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3472 if(skill202)
3474 level = skill202/5;
3479 // select center of summon position
3480 float center_x = m_targets.m_destX;
3481 float center_y = m_targets.m_destY;
3482 float center_z = m_targets.m_destZ;
3484 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3486 int32 amount = damage > 0 ? damage : 1;
3488 for(int32 count = 0; count < amount; ++count)
3490 float px, py, pz;
3491 // If dest location if present
3492 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3494 // Summon 1 unit in dest location
3495 if (count == 0)
3497 px = m_targets.m_destX;
3498 py = m_targets.m_destY;
3499 pz = m_targets.m_destZ;
3501 // Summon in random point all other units if location present
3502 else
3503 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3505 // Summon if dest location not present near caster
3506 else
3507 m_caster->GetClosePoint(px,py,pz,3.0f);
3509 int32 duration = GetSpellDuration(m_spellInfo);
3511 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3513 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3517 void Spell::EffectSummonGuardian(uint32 i)
3519 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3520 if(!pet_entry)
3521 return;
3523 // Jewelery statue case (totem like)
3524 if(m_spellInfo->SpellIconID==2056)
3526 EffectSummonTotem(i);
3527 return;
3530 // set timer for unsummon
3531 int32 duration = GetSpellDuration(m_spellInfo);
3533 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3534 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3535 // so this code hack in fact
3536 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3537 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3538 return; // find old guardian, ignore summon
3540 // in another case summon new
3541 uint32 level = m_caster->getLevel();
3543 // level of pet summoned using engineering item based at engineering skill level
3544 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3546 ItemPrototype const *proto = m_CastItem->GetProto();
3547 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3549 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3550 if(skill202)
3552 level = skill202/5;
3557 // select center of summon position
3558 float center_x = m_targets.m_destX;
3559 float center_y = m_targets.m_destY;
3560 float center_z = m_targets.m_destZ;
3562 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3564 int32 amount = damage > 0 ? damage : 1;
3566 for(int32 count = 0; count < amount; ++count)
3568 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3570 Map *map = m_caster->GetMap();
3571 uint32 pet_number = objmgr.GeneratePetNumber();
3572 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3574 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3575 delete spawnCreature;
3576 return;
3579 float px, py, pz;
3580 // If dest location if present
3581 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3583 // Summon 1 unit in dest location
3584 if (count == 0)
3586 px = m_targets.m_destX;
3587 py = m_targets.m_destY;
3588 pz = m_targets.m_destZ;
3590 // Summon in random point all other units if location present
3591 else
3592 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3594 // Summon if dest location not present near caster
3595 else
3596 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3598 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3600 if(!spawnCreature->IsPositionValid())
3602 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3603 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3604 delete spawnCreature;
3605 return;
3608 if(duration > 0)
3609 spawnCreature->SetDuration(duration);
3611 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3612 spawnCreature->setPowerType(POWER_MANA);
3613 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3614 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3615 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3616 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3617 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3618 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3619 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3621 spawnCreature->InitStatsForLevel(level);
3622 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3624 spawnCreature->AIM_Initialize();
3626 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3627 ((Player*)m_caster)->AddGuardian(spawnCreature);
3629 map->Add((Creature*)spawnCreature);
3633 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3635 if(!unitTarget)
3636 return;
3638 if(unitTarget->isInFlight())
3639 return;
3641 uint32 mapid = m_caster->GetMapId();
3642 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3644 float fx,fy,fz;
3645 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3647 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3648 ((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));
3649 else
3650 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3653 void Spell::EffectLearnSkill(uint32 i)
3655 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3656 return;
3658 if(damage < 0)
3659 return;
3661 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3662 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3663 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3666 void Spell::EffectAddHonor(uint32 /*i*/)
3668 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3669 return;
3671 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3673 // TODO: find formula for honor reward based on player's level!
3675 // now fixed only for level 70 players:
3676 if (((Player*)unitTarget)->getLevel() == 70)
3677 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3680 void Spell::EffectTradeSkill(uint32 /*i*/)
3682 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3683 return;
3684 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3685 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3686 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3689 void Spell::EffectEnchantItemPerm(uint32 i)
3691 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3692 return;
3693 if (!itemTarget)
3694 return;
3696 Player* p_caster = (Player*)m_caster;
3698 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3700 if (m_spellInfo->EffectMiscValue[i])
3702 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3704 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3705 if(!pEnchant)
3706 return;
3708 // item can be in trade slot and have owner diff. from caster
3709 Player* item_owner = itemTarget->GetOwner();
3710 if(!item_owner)
3711 return;
3713 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3715 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3716 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3717 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3718 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3721 // remove old enchanting before applying new if equipped
3722 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3724 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3726 // add new enchanting if equipped
3727 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3731 void Spell::EffectEnchantItemTmp(uint32 i)
3733 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3734 return;
3736 Player* p_caster = (Player*)m_caster;
3738 if(!itemTarget)
3739 return;
3741 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3743 // Shaman Rockbiter Weapon
3744 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3746 int32 enchnting_damage = m_currentBasePoints[1]+1;
3748 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3749 // with already applied percent bonus from Elemental Weapons talent
3750 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3751 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3752 switch(enchnting_damage)
3754 // Rank 1
3755 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3756 // Rank 2
3757 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3758 case 5: enchant_id = 3025; break; // 20%
3759 // Rank 3
3760 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3761 case 7: enchant_id = 3027; break; // 20%
3762 // Rank 4
3763 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3764 case 10: enchant_id = 503; break; // 14%
3765 case 11: enchant_id = 3031; break; // 20%
3766 // Rank 5
3767 case 15: enchant_id = 3035; break; // 0%
3768 case 16: enchant_id = 1663; break; // 7%
3769 case 17: enchant_id = 3033; break; // 14%
3770 case 18: enchant_id = 3034; break; // 20%
3771 // Rank 6
3772 case 28: enchant_id = 3038; break; // 0%
3773 case 29: enchant_id = 683; break; // 7%
3774 case 31: enchant_id = 3036; break; // 14%
3775 case 33: enchant_id = 3037; break; // 20%
3776 // Rank 7
3777 case 40: enchant_id = 3041; break; // 0%
3778 case 42: enchant_id = 1664; break; // 7%
3779 case 45: enchant_id = 3039; break; // 14%
3780 case 48: enchant_id = 3040; break; // 20%
3781 // Rank 8
3782 case 49: enchant_id = 3044; break; // 0%
3783 case 52: enchant_id = 2632; break; // 7%
3784 case 55: enchant_id = 3042; break; // 14%
3785 case 58: enchant_id = 3043; break; // 20%
3786 // Rank 9
3787 case 62: enchant_id = 2633; break; // 0%
3788 case 66: enchant_id = 3018; break; // 7%
3789 case 70: enchant_id = 3019; break; // 14%
3790 case 74: enchant_id = 3020; break; // 20%
3791 default:
3792 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3793 return;
3797 if (!enchant_id)
3799 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3800 return;
3803 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3804 if(!pEnchant)
3806 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3807 return;
3810 // select enchantment duration
3811 uint32 duration;
3813 // rogue family enchantments exception by duration
3814 if(m_spellInfo->Id==38615)
3815 duration = 1800; // 30 mins
3816 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3817 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3818 duration = 3600; // 1 hour
3819 // shaman family enchantments
3820 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3821 duration = 1800; // 30 mins
3822 // other cases with this SpellVisual already selected
3823 else if(m_spellInfo->SpellVisual==215)
3824 duration = 1800; // 30 mins
3825 // some fishing pole bonuses
3826 else if(m_spellInfo->SpellVisual==563)
3827 duration = 600; // 10 mins
3828 // shaman rockbiter enchantments
3829 else if(m_spellInfo->SpellVisual==0)
3830 duration = 1800; // 30 mins
3831 else if(m_spellInfo->Id==29702)
3832 duration = 300; // 5 mins
3833 else if(m_spellInfo->Id==37360)
3834 duration = 300; // 5 mins
3835 // default case
3836 else
3837 duration = 3600; // 1 hour
3839 // item can be in trade slot and have owner diff. from caster
3840 Player* item_owner = itemTarget->GetOwner();
3841 if(!item_owner)
3842 return;
3844 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3846 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3847 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3848 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3849 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3852 // remove old enchanting before applying new if equipped
3853 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3855 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3857 // add new enchanting if equipped
3858 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3861 void Spell::EffectTameCreature(uint32 /*i*/)
3863 if(m_caster->GetPetGUID())
3864 return;
3866 if(!unitTarget)
3867 return;
3869 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3870 return;
3872 Creature* creatureTarget = (Creature*)unitTarget;
3874 if(creatureTarget->isPet())
3875 return;
3877 if(m_caster->getClass() != CLASS_HUNTER)
3878 return;
3880 // cast finish successfully
3881 //SendChannelUpdate(0);
3882 finish();
3884 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3886 // kill original creature
3887 creatureTarget->setDeathState(JUST_DIED);
3888 creatureTarget->RemoveCorpse();
3889 creatureTarget->SetHealth(0); // just for nice GM-mode view
3891 // prepare visual effect for levelup
3892 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
3894 // add to world
3895 pet->GetMap()->Add((Creature*)pet);
3897 // visual effect for levelup
3898 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
3900 // caster have pet now
3901 m_caster->SetPet(pet);
3903 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3905 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3906 ((Player*)m_caster)->PetSpellInitialize();
3910 void Spell::EffectSummonPet(uint32 i)
3912 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3914 Pet *OldSummon = m_caster->GetPet();
3916 // if pet requested type already exist
3917 if( OldSummon )
3919 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3921 // pet in corpse state can't be summoned
3922 if( OldSummon->isDead() )
3923 return;
3925 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
3926 OldSummon->SetMapId(m_caster->GetMapId());
3928 float px, py, pz;
3929 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3931 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3932 m_caster->GetMap()->Add((Creature*)OldSummon);
3934 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
3936 ((Player*)m_caster)->PetSpellInitialize();
3938 return;
3941 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3942 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
3943 else
3944 return;
3947 Pet* NewSummon = new Pet;
3949 // petentry==0 for hunter "call pet" (current pet summoned if any)
3950 if(NewSummon->LoadPetFromDB(m_caster,petentry))
3952 if(NewSummon->getPetType()==SUMMON_PET)
3954 // Remove Demonic Sacrifice auras (known pet)
3955 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
3956 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
3958 if((*itr)->GetModifier()->m_miscvalue==2228)
3960 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
3961 itr = auraClassScripts.begin();
3963 else
3964 ++itr;
3968 return;
3971 // not error in case fail hunter call pet
3972 if(!petentry)
3974 delete NewSummon;
3975 return;
3978 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
3980 if(!cInfo)
3982 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
3983 delete NewSummon;
3984 return;
3987 Map *map = m_caster->GetMap();
3988 uint32 pet_number = objmgr.GeneratePetNumber();
3989 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
3991 delete NewSummon;
3992 return;
3995 float px, py, pz;
3996 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
3998 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4000 if(!NewSummon->IsPositionValid())
4002 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4003 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4004 delete NewSummon;
4005 return;
4008 uint32 petlevel = m_caster->getLevel();
4009 NewSummon->setPetType(SUMMON_PET);
4011 uint32 faction = m_caster->getFaction();
4012 if(m_caster->GetTypeId() == TYPEID_UNIT)
4014 if ( ((Creature*)m_caster)->isTotem() )
4015 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4016 else
4017 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4020 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4021 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4022 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4023 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4024 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4025 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4026 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4027 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4028 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4029 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4031 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4032 // this enables pet details window (Shift+P)
4034 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4035 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4037 NewSummon->InitStatsForLevel(petlevel);
4038 NewSummon->InitPetCreateSpells();
4040 if(NewSummon->getPetType()==SUMMON_PET)
4042 // Remove Demonic Sacrifice auras (new pet)
4043 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4044 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4046 if((*itr)->GetModifier()->m_miscvalue==2228)
4048 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4049 itr = auraClassScripts.begin();
4051 else
4052 ++itr;
4055 // generate new name for summon pet
4056 std::string new_name=objmgr.GeneratePetName(petentry);
4057 if(!new_name.empty())
4058 NewSummon->SetName(new_name);
4060 else if(NewSummon->getPetType()==HUNTER_PET)
4061 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4063 NewSummon->AIM_Initialize();
4064 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4065 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4067 map->Add((Creature*)NewSummon);
4069 m_caster->SetPet(NewSummon);
4070 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4072 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4074 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4075 ((Player*)m_caster)->PetSpellInitialize();
4079 void Spell::EffectLearnPetSpell(uint32 i)
4081 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4082 return;
4084 Player *_player = (Player*)m_caster;
4086 Pet *pet = _player->GetPet();
4087 if(!pet)
4088 return;
4089 if(!pet->isAlive())
4090 return;
4092 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4093 if(!learn_spellproto)
4094 return;
4096 pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id));
4097 pet->learnSpell(learn_spellproto->Id);
4099 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4100 _player->PetSpellInitialize();
4103 void Spell::EffectTaunt(uint32 /*i*/)
4105 // this effect use before aura Taunt apply for prevent taunt already attacking target
4106 // for spell as marked "non effective at already attacking target"
4107 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4109 if(unitTarget->getVictim()==m_caster)
4111 SendCastResult(SPELL_FAILED_DONT_REPORT);
4112 return;
4116 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4117 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4118 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4121 void Spell::EffectWeaponDmg(uint32 i)
4123 if(!unitTarget)
4124 return;
4125 if(!unitTarget->isAlive())
4126 return;
4128 // multiple weapon dmg effect workaround
4129 // execute only the last weapon damage
4130 // and handle all effects at once
4131 for (int j = 0; j < 3; j++)
4133 switch(m_spellInfo->Effect[j])
4135 case SPELL_EFFECT_WEAPON_DAMAGE:
4136 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4137 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4138 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4139 if (j < i) // we must calculate only at last weapon effect
4140 return;
4141 break;
4145 // some spell specific modifiers
4146 bool customBonusDamagePercentMod = false;
4147 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4148 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4149 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4150 bool normalized = false;
4152 int32 spell_bonus = 0; // bonus specific for spell
4153 switch(m_spellInfo->SpellFamilyName)
4155 case SPELLFAMILY_WARRIOR:
4157 // Whirlwind, single only spell with 2 weapon white damage apply if have
4158 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4160 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4161 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4163 // Devastate bonus and sunder armor refresh
4164 else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
4166 customBonusDamagePercentMod = true;
4167 bonusDamagePercentMod = 0.0f; // only applied if auras found
4169 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4170 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4172 SpellEntry const *proto = (*itr)->GetSpellProto();
4173 if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
4175 int32 duration = GetSpellDuration(proto);
4176 (*itr)->SetAuraDuration(duration);
4177 (*itr)->UpdateAuraDuration();
4178 bonusDamagePercentMod += 1.0f; // +100%
4182 break;
4184 case SPELLFAMILY_ROGUE:
4186 // Ambush
4187 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4189 customBonusDamagePercentMod = true;
4190 bonusDamagePercentMod = 2.5f; // 250%
4192 // Mutilate (for each hand)
4193 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4195 bool found = false;
4196 // fast check
4197 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4198 found = true;
4199 // full aura scan
4200 else
4202 Unit::AuraMap const& auras = unitTarget->GetAuras();
4203 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4205 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4207 found = true;
4208 break;
4213 if(found)
4214 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4216 break;
4218 case SPELLFAMILY_PALADIN:
4220 // Seal of Command - receive benefit from Spell Damage and Healing
4221 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4223 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4224 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4226 break;
4228 case SPELLFAMILY_SHAMAN:
4230 // Skyshatter Harness item set bonus
4231 // Stormstrike
4232 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4234 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4235 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4237 // Stormstrike AP Buff
4238 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4240 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4241 break;
4248 int32 fixed_bonus = 0;
4249 for (int j = 0; j < 3; j++)
4251 switch(m_spellInfo->Effect[j])
4253 case SPELL_EFFECT_WEAPON_DAMAGE:
4254 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4255 fixed_bonus += CalculateDamage(j,unitTarget);
4256 break;
4257 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4258 fixed_bonus += CalculateDamage(j,unitTarget);
4259 normalized = true;
4260 break;
4261 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4262 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4264 // applied only to prev.effects fixed damage
4265 if(customBonusDamagePercentMod)
4266 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4267 else
4268 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4269 break;
4270 default:
4271 break; // not weapon damage effect, just skip
4275 // non-weapon damage
4276 int32 bonus = spell_bonus + fixed_bonus;
4278 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4279 if(bonus)
4281 UnitMods unitMod;
4282 switch(m_attackType)
4284 default:
4285 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4286 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4287 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4290 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4291 bonus = int32(bonus*weapon_total_pct);
4294 // + weapon damage with applied weapon% dmg to base weapon damage in call
4295 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4297 // total damage
4298 bonus = int32(bonus*totalDamagePercentMod);
4300 // prevent negative damage
4301 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4303 // Add melee damage bonuses (also check for negative)
4304 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4305 m_damage+= eff_damage;
4307 // Hemorrhage
4308 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4310 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4311 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4314 // Mangle (Cat): CP
4315 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4317 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4318 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4321 // take ammo
4322 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4324 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4326 // wands don't have ammo
4327 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4328 return;
4330 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4332 if(pItem->GetMaxStackCount()==1)
4334 // decrease durability for non-stackable throw weapon
4335 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4337 else
4339 // decrease items amount for stackable throw weapon
4340 uint32 count = 1;
4341 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4344 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4345 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4349 void Spell::EffectThreat(uint32 /*i*/)
4351 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4352 return;
4354 if(!unitTarget->CanHaveThreatList())
4355 return;
4357 unitTarget->AddThreat(m_caster, float(damage));
4360 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4362 if(!unitTarget)
4363 return;
4364 if(!unitTarget->isAlive())
4365 return;
4367 uint32 heal = m_caster->GetMaxHealth();
4369 m_healing+=heal;
4372 void Spell::EffectInterruptCast(uint32 /*i*/)
4374 if(!unitTarget)
4375 return;
4376 if(!unitTarget->isAlive())
4377 return;
4379 // TODO: not all spells that used this effect apply cooldown at school spells
4380 // also exist case: apply cooldown to interrupted cast only and to all spells
4381 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4383 if (unitTarget->m_currentSpells[i])
4385 // check if we can interrupt spell
4386 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4388 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4389 unitTarget->InterruptSpell(i,false);
4395 void Spell::EffectSummonObjectWild(uint32 i)
4397 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4399 GameObject* pGameObj = new GameObject;
4401 WorldObject* target = focusObject;
4402 if( !target )
4403 target = m_caster;
4405 float x,y,z;
4406 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4408 x = m_targets.m_destX;
4409 y = m_targets.m_destY;
4410 z = m_targets.m_destZ;
4412 else
4413 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4415 Map *map = target->GetMap();
4417 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4418 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4420 delete pGameObj;
4421 return;
4424 int32 duration = GetSpellDuration(m_spellInfo);
4425 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4426 pGameObj->SetSpellId(m_spellInfo->Id);
4428 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4429 m_caster->AddGameObject(pGameObj);
4430 map->Add(pGameObj);
4432 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4434 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4436 Player *pl = (Player*)m_caster;
4437 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4438 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4440 uint32 team = ALLIANCE;
4442 if(pl->GetTeam() == team)
4443 team = HORDE;
4445 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4450 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4452 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4454 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4455 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4457 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4462 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4464 GameObject* linkedGO = new GameObject;
4465 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4466 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4468 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4469 linkedGO->SetSpellId(m_spellInfo->Id);
4471 m_caster->AddGameObject(linkedGO);
4472 map->Add(linkedGO);
4474 else
4476 delete linkedGO;
4477 linkedGO = NULL;
4478 return;
4483 void Spell::EffectScriptEffect(uint32 effIndex)
4485 // TODO: we must implement hunter pet summon at login there (spell 6962)
4487 // by spell id
4488 switch(m_spellInfo->Id)
4490 // PX-238 Winter Wondervolt TRAP
4491 case 26275:
4493 if( unitTarget->HasAura(26272,0)
4494 || unitTarget->HasAura(26157,0)
4495 || unitTarget->HasAura(26273,0)
4496 || unitTarget->HasAura(26274,0))
4497 return;
4499 uint32 iTmpSpellId;
4501 switch(urand(0,3))
4503 case 0:
4504 iTmpSpellId = 26272;
4505 break;
4506 case 1:
4507 iTmpSpellId = 26157;
4508 break;
4509 case 2:
4510 iTmpSpellId = 26273;
4511 break;
4512 case 3:
4513 iTmpSpellId = 26274;
4514 break;
4517 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4519 return;
4522 // Bending Shinbone
4523 case 8856:
4525 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4526 return;
4528 uint32 spell_id = 0;
4529 switch(urand(1,5))
4531 case 1: spell_id = 8854; break;
4532 default: spell_id = 8855; break;
4535 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4536 return;
4539 // Healthstone creating spells
4540 case 6201:
4541 case 6202:
4542 case 5699:
4543 case 11729:
4544 case 11730:
4545 case 27230:
4547 uint32 itemtype;
4548 uint32 rank = 0;
4549 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4550 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4552 if((*i)->GetId() == 18692)
4554 rank = 1;
4555 break;
4557 else if((*i)->GetId() == 18693)
4559 rank = 2;
4560 break;
4564 static uint32 const itypes[6][3] = {
4565 { 5512,19004,19005}, // Minor Healthstone
4566 { 5511,19006,19007}, // Lesser Healthstone
4567 { 5509,19008,19009}, // Healthstone
4568 { 5510,19010,19011}, // Greater Healthstone
4569 { 9421,19012,19013}, // Major Healthstone
4570 {22103,22104,22105} // Master Healthstone
4573 switch(m_spellInfo->Id)
4575 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4576 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4577 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4578 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4579 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4580 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4581 default:
4582 return;
4584 DoCreateItem( effIndex, itemtype );
4585 return;
4587 // Brittle Armor - need remove one 24575 Brittle Armor aura
4588 case 24590:
4589 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4590 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4591 return;
4592 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4593 case 26465:
4594 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4595 return;
4596 // Orb teleport spells
4597 case 25140:
4598 case 25143:
4599 case 25650:
4600 case 25652:
4601 case 29128:
4602 case 29129:
4603 case 35376:
4604 case 35727:
4606 if(!unitTarget)
4607 return;
4609 uint32 spellid;
4610 switch(m_spellInfo->Id)
4612 case 25140: spellid = 32571; break;
4613 case 25143: spellid = 32572; break;
4614 case 25650: spellid = 30140; break;
4615 case 25652: spellid = 30141; break;
4616 case 29128: spellid = 32568; break;
4617 case 29129: spellid = 32569; break;
4618 case 35376: spellid = 25649; break;
4619 case 35727: spellid = 35730; break;
4620 default:
4621 return;
4624 unitTarget->CastSpell(unitTarget,spellid,false);
4625 return;
4628 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4629 case 22539:
4630 case 22972:
4631 case 22975:
4632 case 22976:
4633 case 22977:
4634 case 22978:
4635 case 22979:
4636 case 22980:
4637 case 22981:
4638 case 22982:
4639 case 22983:
4640 case 22984:
4641 case 22985:
4643 if(!unitTarget || !unitTarget->isAlive())
4644 return;
4646 // Onyxia Scale Cloak
4647 if(unitTarget->GetDummyAura(22683))
4648 return;
4650 // Shadow Flame
4651 m_caster->CastSpell(unitTarget, 22682, true);
4652 return;
4654 break;
4656 // Summon Black Qiraji Battle Tank
4657 case 26656:
4659 if(!unitTarget)
4660 return;
4662 // Prevent stacking of mounts
4663 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4665 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4666 if (unitTarget->GetAreaId() == 3428)
4667 unitTarget->CastSpell(unitTarget, 25863, false);
4668 else
4669 unitTarget->CastSpell(unitTarget, 26655, false);
4670 break;
4672 // Piccolo of the Flaming Fire
4673 case 17512:
4675 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4676 return;
4677 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4678 break;
4681 // Dreaming Glory
4682 case 28698:
4684 if(!unitTarget)
4685 return;
4686 unitTarget->CastSpell(unitTarget, 28694, true);
4687 break;
4690 // Netherbloom
4691 case 28702:
4693 if(!unitTarget)
4694 return;
4695 // 25% chance of casting a random buff
4696 if(roll_chance_i(75))
4697 return;
4699 // triggered spells are 28703 to 28707
4700 // Note: some sources say, that there was the possibility of
4701 // receiving a debuff. However, this seems to be removed by a patch.
4702 const uint32 spellid = 28703;
4704 // don't overwrite an existing aura
4705 for(uint8 i=0; i<5; i++)
4706 if(unitTarget->HasAura(spellid+i, 0))
4707 return;
4708 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4709 break;
4712 // Nightmare Vine
4713 case 28720:
4715 if(!unitTarget)
4716 return;
4717 // 25% chance of casting Nightmare Pollen
4718 if(roll_chance_i(75))
4719 return;
4720 unitTarget->CastSpell(unitTarget, 28721, true);
4721 break;
4724 // Mirren's Drinking Hat
4725 case 29830:
4727 uint32 item = 0;
4728 switch ( urand(1,6) )
4730 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4731 case 4: case 5: item = 23585; break;// Stouthammer Lite
4732 case 6: item = 23586; break;// Aerie Peak Pale Ale
4734 if (item)
4735 DoCreateItem(effIndex,item);
4736 break;
4738 // Improved Sprint
4739 case 30918:
4741 // Removes snares and roots.
4742 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4743 Unit::AuraMap& Auras = unitTarget->GetAuras();
4744 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4746 next = iter;
4747 ++next;
4748 Aura *aur = iter->second;
4749 if (!aur->IsPositive()) //only remove negative spells
4751 // check for mechanic mask
4752 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4754 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4755 if(Auras.empty())
4756 break;
4757 else
4758 next = Auras.begin();
4762 break;
4764 case 41126: // Flame Crash
4766 if(!unitTarget)
4767 return;
4769 unitTarget->CastSpell(unitTarget, 41131, true);
4770 break;
4772 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4774 if(!unitTarget)
4775 return;
4777 unitTarget->CastSpell(unitTarget, 44870, true);
4778 break;
4781 // Goblin Weather Machine
4782 case 46203:
4784 if(!unitTarget)
4785 return;
4787 uint32 spellId;
4788 switch(rand()%4)
4790 case 0:
4791 spellId=46740;
4792 break;
4793 case 1:
4794 spellId=46739;
4795 break;
4796 case 2:
4797 spellId=46738;
4798 break;
4799 case 3:
4800 spellId=46736;
4801 break;
4803 unitTarget->CastSpell(unitTarget, spellId, true);
4804 break;
4806 //5,000 Gold
4807 case 46642:
4809 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4810 return;
4812 ((Player*)unitTarget)->ModifyMoney(50000000);
4814 break;
4818 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4820 switch(m_spellInfo->SpellFamilyFlags)
4822 // Judgement
4823 case 0x800000:
4825 if(!unitTarget || !unitTarget->isAlive())
4826 return;
4827 uint32 spellId2 = 0;
4829 // all seals have aura dummy
4830 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4831 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4833 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4835 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4836 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4837 continue;
4839 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4840 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4842 if(spellId2 <= 1)
4843 continue;
4845 // found, remove seal
4846 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4848 // Sanctified Judgement
4849 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4850 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4852 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4854 int32 chance = (*i)->GetModifier()->m_amount;
4855 if ( roll_chance_i(chance) )
4857 int32 mana = spellInfo->manaCost;
4858 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4859 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4860 mana = int32(mana* 0.8f);
4861 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4863 break;
4867 break;
4870 m_caster->CastSpell(unitTarget,spellId2,true);
4871 return;
4876 // normal DB scripted effect
4877 if(!unitTarget)
4878 return;
4880 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
4881 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
4884 void Spell::EffectSanctuary(uint32 /*i*/)
4886 if(!unitTarget)
4887 return;
4888 //unitTarget->CombatStop();
4890 unitTarget->CombatStop();
4891 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
4892 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4893 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
4895 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4899 void Spell::EffectAddComboPoints(uint32 /*i*/)
4901 if(!unitTarget)
4902 return;
4904 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4905 return;
4907 if(damage <= 0)
4908 return;
4910 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
4913 void Spell::EffectDuel(uint32 i)
4915 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4916 return;
4918 Player *caster = (Player*)m_caster;
4919 Player *target = (Player*)unitTarget;
4921 // caster or target already have requested duel
4922 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
4923 return;
4925 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4926 // Don't have to check the target's map since you cannot challenge someone across maps
4927 if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530)
4929 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4930 return;
4933 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
4934 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
4936 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4937 return;
4940 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
4941 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
4943 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4944 return;
4947 //CREATE DUEL FLAG OBJECT
4948 GameObject* pGameObj = new GameObject;
4950 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4952 Map *map = m_caster->GetMap();
4953 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4954 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
4955 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
4956 m_caster->GetPositionZ(),
4957 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
4959 delete pGameObj;
4960 return;
4963 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
4964 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
4965 int32 duration = GetSpellDuration(m_spellInfo);
4966 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4967 pGameObj->SetSpellId(m_spellInfo->Id);
4969 m_caster->AddGameObject(pGameObj);
4970 map->Add(pGameObj);
4971 //END
4973 // Send request
4974 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
4975 data << pGameObj->GetGUID();
4976 data << caster->GetGUID();
4977 caster->GetSession()->SendPacket(&data);
4978 target->GetSession()->SendPacket(&data);
4980 // create duel-info
4981 DuelInfo *duel = new DuelInfo;
4982 duel->initiator = caster;
4983 duel->opponent = target;
4984 duel->startTime = 0;
4985 duel->startTimer = 0;
4986 caster->duel = duel;
4988 DuelInfo *duel2 = new DuelInfo;
4989 duel2->initiator = caster;
4990 duel2->opponent = caster;
4991 duel2->startTime = 0;
4992 duel2->startTimer = 0;
4993 target->duel = duel2;
4995 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
4996 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
4999 void Spell::EffectStuck(uint32 /*i*/)
5001 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5002 return;
5004 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5005 return;
5007 Player* pTarget = (Player*)unitTarget;
5009 sLog.outDebug("Spell Effect: Stuck");
5010 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());
5012 if(pTarget->isInFlight())
5013 return;
5015 // homebind location is loaded always
5016 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5018 // Stuck spell trigger Hearthstone cooldown
5019 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5020 if(!spellInfo)
5021 return;
5022 Spell spell(pTarget,spellInfo,true,0);
5023 spell.SendSpellCooldown();
5026 void Spell::EffectSummonPlayer(uint32 /*i*/)
5028 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5029 return;
5031 // Evil Twin (ignore player summon, but hide this for summoner)
5032 if(unitTarget->GetDummyAura(23445))
5033 return;
5035 float x,y,z;
5036 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5038 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5040 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5041 data << uint64(m_caster->GetGUID()); // summoner guid
5042 data << uint32(m_caster->GetZoneId()); // summoner zone
5043 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5044 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5047 static ScriptInfo generateActivateCommand()
5049 ScriptInfo si;
5050 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5051 return si;
5054 void Spell::EffectActivateObject(uint32 effect_idx)
5056 if(!gameObjTarget)
5057 return;
5059 static ScriptInfo activateCommand = generateActivateCommand();
5061 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5063 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5066 void Spell::EffectSummonTotem(uint32 i)
5068 uint8 slot = 0;
5069 switch(m_spellInfo->EffectMiscValueB[i])
5071 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5072 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5073 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5074 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5075 // Battle standard case
5076 case SUMMON_TYPE_TOTEM: slot = 254; break;
5077 // jewelery statue case, like totem without slot
5078 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5079 default: return;
5082 if(slot < MAX_TOTEM)
5084 uint64 guid = m_caster->m_TotemSlot[slot];
5085 if(guid != 0)
5087 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5088 if(OldTotem && OldTotem->isTotem())
5089 ((Totem*)OldTotem)->UnSummon();
5093 uint32 team = 0;
5094 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5095 team = ((Player*)m_caster)->GetTeam();
5097 Totem* pTotem = new Totem;
5099 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5101 delete pTotem;
5102 return;
5105 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5107 float x,y,z;
5108 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5110 // totem must be at same Z in case swimming caster and etc.
5111 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5112 z = m_caster->GetPositionZ();
5114 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5116 if(slot < MAX_TOTEM)
5117 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5119 pTotem->SetOwner(m_caster->GetGUID());
5120 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5122 int32 duration=GetSpellDuration(m_spellInfo);
5123 if(Player* modOwner = m_caster->GetSpellModOwner())
5124 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5125 pTotem->SetDuration(duration);
5127 if (damage) // if not spell info, DB values used
5129 pTotem->SetMaxHealth(damage);
5130 pTotem->SetHealth(damage);
5133 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5134 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5136 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5137 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5139 pTotem->Summon(m_caster);
5141 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5143 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5144 data << uint8(slot);
5145 data << uint64(pTotem->GetGUID());
5146 data << uint32(duration);
5147 data << uint32(m_spellInfo->Id);
5148 ((Player*)m_caster)->SendDirectMessage(&data);
5152 void Spell::EffectEnchantHeldItem(uint32 i)
5154 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5155 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5156 return;
5158 Player* item_owner = (Player*)unitTarget;
5159 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5161 if(!item )
5162 return;
5164 // must be equipped
5165 if(!item ->IsEquipped())
5166 return;
5168 if (m_spellInfo->EffectMiscValue[i])
5170 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5171 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5172 if(!duration)
5173 duration = m_currentBasePoints[i]+1; //Base points after ..
5174 if(!duration)
5175 duration = 10; //10 seconds for enchants which don't have listed duration
5177 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5178 if(!pEnchant)
5179 return;
5181 // Always go to temp enchantment slot
5182 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5184 // Enchantment will not be applied if a different one already exists
5185 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5186 return;
5188 // Apply the temporary enchantment
5189 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5190 item_owner->ApplyEnchantment(item,slot,true);
5194 void Spell::EffectDisEnchant(uint32 /*i*/)
5196 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5197 return;
5199 Player* p_caster = (Player*)m_caster;
5200 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5201 return;
5203 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5205 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5207 // item will be removed at disenchanting end
5210 void Spell::EffectInebriate(uint32 /*i*/)
5212 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5213 return;
5215 Player *player = (Player*)unitTarget;
5216 uint16 currentDrunk = player->GetDrunkValue();
5217 uint16 drunkMod = damage * 256;
5218 if (currentDrunk + drunkMod > 0xFFFF)
5219 currentDrunk = 0xFFFF;
5220 else
5221 currentDrunk += drunkMod;
5222 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5225 void Spell::EffectFeedPet(uint32 i)
5227 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5228 return;
5230 Player *_player = (Player*)m_caster;
5232 if(!itemTarget)
5233 return;
5235 Pet *pet = _player->GetPet();
5236 if(!pet)
5237 return;
5239 if(!pet->isAlive())
5240 return;
5242 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5243 if(benefit <= 0)
5244 return;
5246 uint32 count = 1;
5247 _player->DestroyItemCount(itemTarget,count,true);
5248 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5250 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5253 void Spell::EffectDismissPet(uint32 /*i*/)
5255 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5256 return;
5258 Pet* pet = m_caster->GetPet();
5260 // not let dismiss dead pet
5261 if(!pet||!pet->isAlive())
5262 return;
5264 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5267 void Spell::EffectSummonObject(uint32 i)
5269 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5271 uint8 slot = 0;
5272 switch(m_spellInfo->Effect[i])
5274 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5275 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5276 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5277 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5278 default: return;
5281 uint64 guid = m_caster->m_ObjectSlot[slot];
5282 if(guid != 0)
5284 GameObject* obj = NULL;
5285 if( m_caster )
5286 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5288 if(obj) obj->Delete();
5289 m_caster->m_ObjectSlot[slot] = 0;
5292 GameObject* pGameObj = new GameObject;
5294 float rot2 = sin(m_caster->GetOrientation()/2);
5295 float rot3 = cos(m_caster->GetOrientation()/2);
5297 float x,y,z;
5298 // If dest location if present
5299 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5301 x = m_targets.m_destX;
5302 y = m_targets.m_destY;
5303 z = m_targets.m_destZ;
5305 // Summon in random point all other units if location present
5306 else
5307 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5309 Map *map = m_caster->GetMap();
5310 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5312 delete pGameObj;
5313 return;
5316 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5317 int32 duration = GetSpellDuration(m_spellInfo);
5318 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5319 pGameObj->SetSpellId(m_spellInfo->Id);
5320 m_caster->AddGameObject(pGameObj);
5322 map->Add(pGameObj);
5323 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5324 data << pGameObj->GetGUID();
5325 m_caster->SendMessageToSet(&data,true);
5327 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5330 void Spell::EffectResurrect(uint32 /*effIndex*/)
5332 if(!unitTarget)
5333 return;
5334 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5335 return;
5337 if(unitTarget->isAlive())
5338 return;
5339 if(!unitTarget->IsInWorld())
5340 return;
5342 switch (m_spellInfo->Id)
5344 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5345 case 8342:
5346 if (roll_chance_i(67))
5348 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5349 return;
5351 break;
5352 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5353 case 22999:
5354 if (roll_chance_i(50))
5356 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5357 return;
5359 break;
5360 default:
5361 break;
5364 Player* pTarget = ((Player*)unitTarget);
5366 if(pTarget->isRessurectRequested()) // already have one active request
5367 return;
5369 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5370 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5372 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5373 SendResurrectRequest(pTarget);
5376 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5378 if(!unitTarget || !unitTarget->isAlive())
5379 return;
5381 if( unitTarget->m_extraAttacks )
5382 return;
5384 unitTarget->m_extraAttacks = damage;
5387 void Spell::EffectParry(uint32 /*i*/)
5389 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5391 ((Player*)unitTarget)->SetCanParry(true);
5395 void Spell::EffectBlock(uint32 /*i*/)
5397 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5398 return;
5400 ((Player*)unitTarget)->SetCanBlock(true);
5403 void Spell::EffectMomentMove(uint32 i)
5405 if(unitTarget->isInFlight())
5406 return;
5408 if( m_spellInfo->rangeIndex== 1) //self range
5410 uint32 mapid = m_caster->GetMapId();
5411 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5413 // before caster
5414 float fx,fy,fz;
5415 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5416 float ox,oy,oz;
5417 unitTarget->GetPosition(ox,oy,oz);
5419 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5420 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5422 fx = fx2;
5423 fy = fy2;
5424 fz = fz2;
5425 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5428 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5429 ((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));
5430 else
5431 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5435 void Spell::EffectReputation(uint32 i)
5437 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5438 return;
5440 Player *_player = (Player*)unitTarget;
5442 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5444 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5446 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5448 if(!factionEntry)
5449 return;
5451 _player->ModifyFactionReputation(factionEntry,rep_change);
5454 void Spell::EffectQuestComplete(uint32 i)
5456 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5457 return;
5459 Player *_player = (Player*)m_caster;
5461 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5462 _player->AreaExploredOrEventHappens(quest_id);
5465 void Spell::EffectSelfResurrect(uint32 i)
5467 if(!unitTarget || unitTarget->isAlive())
5468 return;
5469 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5470 return;
5471 if(!unitTarget->IsInWorld())
5472 return;
5474 uint32 health = 0;
5475 uint32 mana = 0;
5477 // flat case
5478 if(damage < 0)
5480 health = uint32(-damage);
5481 mana = m_spellInfo->EffectMiscValue[i];
5483 // percent case
5484 else
5486 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5487 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5488 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5491 Player *plr = ((Player*)unitTarget);
5492 plr->ResurrectPlayer(0.0f);
5494 plr->SetHealth( health );
5495 plr->SetPower(POWER_MANA, mana );
5496 plr->SetPower(POWER_RAGE, 0 );
5497 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5499 plr->SpawnCorpseBones();
5501 plr->SaveToDB();
5504 void Spell::EffectSkinning(uint32 /*i*/)
5506 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5507 return;
5508 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5509 return;
5511 Creature* creature = (Creature*) unitTarget;
5512 int32 targetLevel = creature->getLevel();
5514 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5516 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5517 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5519 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5521 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5523 // Double chances for elites
5524 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5527 void Spell::EffectCharge(uint32 /*i*/)
5529 if(!unitTarget || !m_caster)
5530 return;
5532 float x, y, z;
5533 unitTarget->GetContactPoint(m_caster, x, y, z);
5534 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5535 ((Creature *)unitTarget)->StopMoving();
5537 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5538 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5540 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5541 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5543 // not all charge effects used in negative spells
5544 if ( !IsPositiveSpell(m_spellInfo->Id))
5545 m_caster->Attack(unitTarget,true);
5548 void Spell::EffectSummonCritter(uint32 i)
5550 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5551 return;
5552 Player* player = (Player*)m_caster;
5554 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5555 if(!pet_entry)
5556 return;
5558 Pet* old_critter = player->GetMiniPet();
5560 // for same pet just despawn
5561 if(old_critter && old_critter->GetEntry() == pet_entry)
5563 player->RemoveMiniPet();
5564 return;
5567 // despawn old pet before summon new
5568 if(old_critter)
5569 player->RemoveMiniPet();
5571 // summon new pet
5572 Pet* critter = new Pet(MINI_PET);
5574 Map *map = m_caster->GetMap();
5575 uint32 pet_number = objmgr.GeneratePetNumber();
5576 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5577 map, pet_entry, pet_number))
5579 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5580 delete critter;
5581 return;
5584 float x,y,z;
5585 // If dest location if present
5586 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5588 x = m_targets.m_destX;
5589 y = m_targets.m_destY;
5590 z = m_targets.m_destZ;
5592 // Summon if dest location not present near caster
5593 else
5594 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5596 critter->Relocate(x,y,z,m_caster->GetOrientation());
5598 if(!critter->IsPositionValid())
5600 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5601 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5602 delete critter;
5603 return;
5606 critter->SetOwnerGUID(m_caster->GetGUID());
5607 critter->SetCreatorGUID(m_caster->GetGUID());
5608 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5609 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5611 critter->AIM_Initialize();
5612 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5613 critter->SetMaxHealth(1);
5614 critter->SetHealth(1);
5615 critter->SetLevel(1);
5617 // set timer for unsummon
5618 int32 duration = GetSpellDuration(m_spellInfo);
5619 if(duration > 0)
5620 critter->SetDuration(duration);
5622 std::string name = player->GetName();
5623 name.append(petTypeSuffix[critter->getPetType()]);
5624 critter->SetName( name );
5625 player->SetMiniPet(critter);
5627 map->Add((Creature*)critter);
5630 void Spell::EffectKnockBack(uint32 i)
5632 if(!unitTarget || !m_caster)
5633 return;
5635 // Effect only works on players
5636 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5637 return;
5639 float vsin = sin(m_caster->GetAngle(unitTarget));
5640 float vcos = cos(m_caster->GetAngle(unitTarget));
5642 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5643 data.append(unitTarget->GetPackGUID());
5644 data << uint32(0); // Sequence
5645 data << float(vcos); // x direction
5646 data << float(vsin); // y direction
5647 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5648 data << float(damage/-10); // Z Movement speed (vertical)
5650 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5653 void Spell::EffectSendTaxi(uint32 i)
5655 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5656 return;
5658 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5659 if(!entry)
5660 return;
5662 std::vector<uint32> nodes;
5664 nodes.resize(2);
5665 nodes[0] = entry->from;
5666 nodes[1] = entry->to;
5668 uint32 mountid = 0;
5669 switch(m_spellInfo->Id)
5671 case 31606: //Stormcrow Amulet
5672 mountid = 17447;
5673 break;
5674 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5675 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5676 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5677 mountid = 22840;
5678 break;
5679 case 34905: //Stealth Flight
5680 mountid = 6851;
5681 break;
5684 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5688 void Spell::EffectPlayerPull(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(unitTarget->GetAngle(m_caster));
5698 float vcos = cos(unitTarget->GetAngle(m_caster));
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 // Horizontal speed
5706 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5707 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5709 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5712 void Spell::EffectDispelMechanic(uint32 i)
5714 if(!unitTarget)
5715 return;
5717 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5719 Unit::AuraMap& Auras = unitTarget->GetAuras();
5720 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5722 next = iter;
5723 ++next;
5724 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5725 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5727 unitTarget->RemoveAurasDueToSpell(spell->Id);
5728 if(Auras.empty())
5729 break;
5730 else
5731 next = Auras.begin();
5734 return;
5737 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5739 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5740 return;
5741 Player *_player = (Player*)m_caster;
5742 Pet *pet = _player->GetPet();
5743 if(!pet)
5744 return;
5745 if(pet->isAlive())
5746 return;
5747 if(damage < 0)
5748 return;
5749 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5750 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5751 pet->setDeathState( ALIVE );
5752 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5753 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5755 pet->AIM_Initialize();
5757 _player->PetSpellInitialize();
5758 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5761 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5763 float mana = 0;
5764 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5766 if(!m_caster->m_TotemSlot[slot])
5767 continue;
5769 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5770 if(totem && totem->isTotem())
5772 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5773 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5774 if(spellInfo)
5775 mana += spellInfo->manaCost * damage / 100;
5776 ((Totem*)totem)->UnSummon();
5780 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5781 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5784 void Spell::EffectDurabilityDamage(uint32 i)
5786 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5787 return;
5789 int32 slot = m_spellInfo->EffectMiscValue[i];
5791 // FIXME: some spells effects have value -1/-2
5792 // Possibly its mean -1 all player equipped items and -2 all items
5793 if(slot < 0)
5795 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5796 return;
5799 // invalid slot value
5800 if(slot >= INVENTORY_SLOT_BAG_END)
5801 return;
5803 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5804 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5807 void Spell::EffectDurabilityDamagePCT(uint32 i)
5809 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5810 return;
5812 int32 slot = m_spellInfo->EffectMiscValue[i];
5814 // FIXME: some spells effects have value -1/-2
5815 // Possibly its mean -1 all player equipped items and -2 all items
5816 if(slot < 0)
5818 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5819 return;
5822 // invalid slot value
5823 if(slot >= INVENTORY_SLOT_BAG_END)
5824 return;
5826 if(damage <= 0)
5827 return;
5829 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5830 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
5833 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
5835 if(!unitTarget)
5836 return;
5838 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5841 void Spell::EffectTransmitted(uint32 effIndex)
5843 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
5845 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
5847 if (!goinfo)
5849 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
5850 return;
5853 float fx,fy,fz;
5855 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5857 fx = m_targets.m_destX;
5858 fy = m_targets.m_destY;
5859 fz = m_targets.m_destZ;
5861 //FIXME: this can be better check for most objects but still hack
5862 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
5864 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
5865 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5867 else
5869 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5870 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5871 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
5873 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5876 Map *cMap = m_caster->GetMap();
5878 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
5880 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
5881 { // but this is not proper, we really need to ignore not materialized objects
5882 SendCastResult(SPELL_FAILED_NOT_HERE);
5883 SendChannelUpdate(0);
5884 return;
5887 // replace by water level in this case
5888 fz = cMap->GetWaterLevel(fx,fy);
5890 // if gameobject is summoning object, it should be spawned right on caster's position
5891 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5893 m_caster->GetPosition(fx,fy,fz);
5896 GameObject* pGameObj = new GameObject;
5898 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5899 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5901 delete pGameObj;
5902 return;
5905 int32 duration = GetSpellDuration(m_spellInfo);
5907 switch(goinfo->type)
5909 case GAMEOBJECT_TYPE_FISHINGNODE:
5911 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
5912 // Orientation3
5913 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 );
5914 // Orientation4
5915 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 );
5916 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5918 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5919 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5920 int32 lastSec;
5921 switch(urand(0, 3))
5923 case 0: lastSec = 3; break;
5924 case 1: lastSec = 7; break;
5925 case 2: lastSec = 13; break;
5926 case 3: lastSec = 17; break;
5929 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
5930 break;
5932 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
5934 if(m_caster->GetTypeId()==TYPEID_PLAYER)
5936 pGameObj->AddUniqueUse((Player*)m_caster);
5937 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5939 break;
5941 case GAMEOBJECT_TYPE_FISHINGHOLE:
5942 case GAMEOBJECT_TYPE_CHEST:
5943 default:
5945 break;
5949 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5951 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
5953 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
5954 pGameObj->SetSpellId(m_spellInfo->Id);
5956 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
5957 //m_caster->AddGameObject(pGameObj);
5958 //m_ObjToDel.push_back(pGameObj);
5960 cMap->Add(pGameObj);
5962 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5963 data << uint64(pGameObj->GetGUID());
5964 m_caster->SendMessageToSet(&data,true);
5966 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
5968 GameObject* linkedGO = new GameObject;
5969 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
5970 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5972 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5973 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
5974 linkedGO->SetSpellId(m_spellInfo->Id);
5975 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
5977 linkedGO->GetMap()->Add(linkedGO);
5979 else
5981 delete linkedGO;
5982 linkedGO = NULL;
5983 return;
5988 void Spell::EffectProspecting(uint32 /*i*/)
5990 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5991 return;
5993 Player* p_caster = (Player*)m_caster;
5994 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
5995 return;
5997 if(itemTarget->GetCount() < 5)
5998 return;
6000 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6002 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6003 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6004 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6007 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6010 void Spell::EffectSkill(uint32 /*i*/)
6012 sLog.outDebug("WORLD: SkillEFFECT");
6015 void Spell::EffectSummonDemon(uint32 i)
6017 float px = m_targets.m_destX;
6018 float py = m_targets.m_destY;
6019 float pz = m_targets.m_destZ;
6021 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6022 if (!Charmed)
6023 return;
6025 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6026 Charmed->SetLevel(m_caster->getLevel());
6028 // TODO: Add damage/mana/hp according to level
6030 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6032 // Enslave demon effect, without mana cost and cooldown
6033 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6035 // Inferno effect
6036 Charmed->CastSpell(Charmed, 22703, true, 0);
6040 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6041 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6042 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6043 This is why we use a half sec delay between the visual effect and the resurrection itself */
6044 void Spell::EffectSpiritHeal(uint32 /*i*/)
6047 if(!unitTarget || unitTarget->isAlive())
6048 return;
6049 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6050 return;
6051 if(!unitTarget->IsInWorld())
6052 return;
6054 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6055 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6056 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6057 ((Player*)unitTarget)->SpawnCorpseBones();
6061 // remove insignia spell effect
6062 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6064 sLog.outDebug("Effect: SkinPlayerCorpse");
6065 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6066 return;
6068 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6071 void Spell::EffectStealBeneficialBuff(uint32 i)
6073 sLog.outDebug("Effect: StealBeneficialBuff");
6075 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6076 return;
6078 std::vector <Aura *> steal_list;
6079 // Create dispel mask by dispel type
6080 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6081 Unit::AuraMap const& auras = unitTarget->GetAuras();
6082 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6084 Aura *aur = (*itr).second;
6085 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6087 // Need check for passive? this
6088 if (aur->IsPositive() && !aur->IsPassive())
6089 steal_list.push_back(aur);
6092 // Ok if exist some buffs for dispel try dispel it
6093 if (!steal_list.empty())
6095 std::list < std::pair<uint32,uint64> > success_list;
6096 int32 list_size = steal_list.size();
6097 // Dispell N = damage buffs (or while exist buffs for dispel)
6098 for (int32 count=0; count < damage && list_size > 0; ++count)
6100 // Random select buff for dispel
6101 Aura *aur = steal_list[urand(0, list_size-1)];
6102 // Not use chance for steal
6103 // TODO possible need do it
6104 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6106 // Remove buff from list for prevent doubles
6107 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6109 Aura *stealed = *j;
6110 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6112 j = steal_list.erase(j);
6113 --list_size;
6115 else
6116 ++j;
6119 // Really try steal and send log
6120 if (!success_list.empty())
6122 int32 count = success_list.size();
6123 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6124 data.append(unitTarget->GetPackGUID()); // Victim GUID
6125 data.append(m_caster->GetPackGUID()); // Caster GUID
6126 data << uint32(m_spellInfo->Id); // Dispell spell id
6127 data << uint8(0); // not used
6128 data << uint32(count); // count
6129 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6131 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6132 data << uint32(spellInfo->Id); // Spell Id
6133 data << uint8(0); // 0 - steals !=0 transfers
6134 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6136 m_caster->SendMessageToSet(&data, true);
6141 void Spell::EffectKillCredit(uint32 i)
6143 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6144 return;
6146 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6149 void Spell::EffectQuestFail(uint32 i)
6151 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6152 return;
6154 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);