Updated spells stuff
[getmangos.git] / src / game / SpellEffects.cpp
blob63adcba421d6d71dcb0fe161fe01fb280904dd2b
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
52 #include "Language.h"
53 #include "SocialMgr.h"
54 #include "Util.h"
55 #include "TemporarySummon.h"
57 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
59 &Spell::EffectNULL, // 0
60 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
61 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
62 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
63 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
64 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
65 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
66 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
67 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
68 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
69 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
70 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
71 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
72 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
73 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
74 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
75 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
76 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
77 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
78 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
79 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
80 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
81 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
82 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
83 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
84 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
85 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
86 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
87 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
88 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
89 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
90 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
91 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
92 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
93 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
94 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
95 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
96 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
97 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
98 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
99 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
100 &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
101 &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
102 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
103 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
104 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
105 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
106 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
107 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
108 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
109 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
110 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
111 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
112 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
113 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
114 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
115 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
116 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
117 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
118 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
119 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
120 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
121 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
122 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
123 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
124 &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
125 &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
126 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
127 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
128 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
129 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
130 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
131 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
132 &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
133 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
134 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
135 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
136 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
137 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
138 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
139 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
140 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
141 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
142 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
143 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
144 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
145 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
146 &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
147 &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
148 &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
149 &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
150 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
151 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
152 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
153 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
154 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
155 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
156 &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
157 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
158 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
159 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
160 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
161 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
162 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
163 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
164 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
165 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
166 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
167 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
168 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
169 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
170 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
171 &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
172 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
173 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
174 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
175 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
176 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
177 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
178 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
179 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
180 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
181 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
182 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
183 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
184 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
185 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
186 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
187 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
188 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
189 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
190 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
191 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
192 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
193 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
194 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
195 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
196 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
197 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
198 &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
199 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
200 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
201 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
202 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
203 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
204 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
205 &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
206 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
207 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
208 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
209 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
210 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
211 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
212 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
213 &Spell::EffectNULL, //154
214 &Spell::EffectNULL, //155 Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
215 &Spell::EffectNULL, //156 Test Add Sockets Enchant
216 &Spell::EffectNULL, //157
217 &Spell::EffectNULL, //158
218 &Spell::EffectNULL //159
221 void Spell::EffectNULL(uint32 /*i*/)
223 sLog.outDebug("WORLD: Spell Effect DUMMY");
226 void Spell::EffectUnused(uint32 /*i*/)
228 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
231 void Spell::EffectResurrectNew(uint32 i)
233 if(!unitTarget || unitTarget->isAlive())
234 return;
236 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
237 return;
239 if(!unitTarget->IsInWorld())
240 return;
242 Player* pTarget = ((Player*)unitTarget);
244 if(pTarget->isRessurectRequested()) // already have one active request
245 return;
247 uint32 health = damage;
248 uint32 mana = m_spellInfo->EffectMiscValue[i];
249 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
250 SendResurrectRequest(pTarget);
253 void Spell::EffectInstaKill(uint32 /*i*/)
255 if( !unitTarget || !unitTarget->isAlive() )
256 return;
258 // Demonic Sacrifice
259 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
261 uint32 entry = unitTarget->GetEntry();
262 uint32 spellID;
263 switch(entry)
265 case 416: spellID=18789; break; //imp
266 case 417: spellID=18792; break; //fellhunter
267 case 1860: spellID=18790; break; //void
268 case 1863: spellID=18791; break; //succubus
269 case 17252: spellID=35701; break; //fellguard
270 default:
271 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
272 return;
275 m_caster->CastSpell(m_caster,spellID,true);
278 if(m_caster==unitTarget) // prevent interrupt message
279 finish();
281 uint32 health = unitTarget->GetHealth();
282 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
285 void Spell::EffectEnvirinmentalDMG(uint32 i)
287 uint32 absorb = 0;
288 uint32 resist = 0;
290 // Note: this hack with damage replace required until GO casting not implemented
291 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
292 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
293 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
295 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
297 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
298 if(m_caster->GetTypeId() == TYPEID_PLAYER)
299 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
302 void Spell::EffectSchoolDMG(uint32 effect_idx)
304 if( unitTarget && unitTarget->isAlive())
306 switch(m_spellInfo->SpellFamilyName)
308 case SPELLFAMILY_GENERIC:
310 //Gore
311 if(m_spellInfo->SpellIconID == 2269 )
313 damage+= rand()%2 ? damage : 0;
316 switch(m_spellInfo->Id) // better way to check unknown
318 // Meteor like spells (divided damage to targets)
319 case 24340: case 26558: case 28884: // Meteor
320 case 36837: case 38903: case 41276: // Meteor
321 case 26789: // Shard of the Fallen Star
322 case 31436: // Malevolent Cleave
323 case 35181: // Dive Bomb
324 case 40810: case 43267: case 43268: // Saber Lash
325 case 42384: // Brutal Swipe
326 case 45150: // Meteor Slash
328 uint32 count = 0;
329 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
330 if(ihit->effectMask & (1<<effect_idx))
331 ++count;
333 damage /= count; // divide to all targets
334 break;
336 // percent from health with min
337 case 25599: // Thundercrash
339 damage = unitTarget->GetHealth() / 2;
340 if(damage < 200)
341 damage = 200;
342 break;
345 break;
348 case SPELLFAMILY_MAGE:
350 // Arcane Blast
351 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
353 m_caster->CastSpell(m_caster,36032,true);
355 break;
357 case SPELLFAMILY_WARRIOR:
359 // Bloodthirst
360 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
362 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
364 // Shield Slam
365 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
366 damage += int32(m_caster->GetShieldBlockValue());
367 // Victory Rush
368 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
370 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
371 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
373 break;
375 case SPELLFAMILY_WARLOCK:
377 // Incinerate Rank 1 & 2
378 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
380 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
381 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
382 damage += int32(damage*0.25);
384 break;
386 case SPELLFAMILY_DRUID:
388 // Ferocious Bite
389 if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
391 // converts each extra point of energy into ($f1+$AP/630) additional damage
392 float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
393 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
394 m_caster->SetPower(POWER_ENERGY,0);
396 // Rake
397 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
399 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
401 // Swipe
402 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
404 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
406 // Starfire
407 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
409 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
410 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
412 // Starfire Bonus (caster)
413 switch((*i)->GetModifier()->m_miscvalue)
415 case 5481: // Nordrassil Regalia - bonus
417 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
418 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
420 // Moonfire or Insect Swarm (target debuff from any casters)
421 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
423 int32 mod = (*i)->GetModifier()->m_amount;
424 damage += damage*mod/100;
425 break;
428 break;
430 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
432 damage += (*i)->GetModifier()->m_amount;
433 break;
438 //Mangle Bonus for the initial damage of Lacerate and Rake
439 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
440 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
442 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
443 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
444 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
446 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
447 break;
450 break;
452 case SPELLFAMILY_ROGUE:
454 // Envenom
455 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
457 // consume from stack dozes not more that have combo-points
458 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
460 // count consumed deadly poison doses at target
461 uint32 doses = 0;
463 // remove consumed poison doses
464 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
465 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
467 // Deadly poison (only attacker applied)
468 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
469 (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
471 --combo;
472 ++doses;
474 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
476 itr = auras.begin();
478 else
479 ++itr;
482 damage *= doses;
483 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
485 // Eviscerate and Envenom Bonus Damage (item set effect)
486 if(m_caster->GetDummyAura(37169))
487 damage += ((Player*)m_caster)->GetComboPoints()*40;
490 // Eviscerate
491 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
493 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
495 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
497 // Eviscerate and Envenom Bonus Damage (item set effect)
498 if(m_caster->GetDummyAura(37169))
499 damage += combo*40;
502 break;
504 case SPELLFAMILY_HUNTER:
506 // Mongoose Bite
507 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
509 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
511 // Arcane Shot
512 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
514 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
516 // Steady Shot
517 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
519 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
520 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
522 //Explosive Trap Effect
523 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
525 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
527 break;
529 case SPELLFAMILY_PALADIN:
531 //Judgement of Vengeance
532 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
534 uint32 stacks = 0;
535 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
536 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
537 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
538 ++stacks;
539 if(!stacks)
540 //No damage if the target isn't affected by this
541 damage = -1;
542 else
543 damage *= stacks;
545 break;
549 if(damage >= 0)
551 uint32 finalDamage;
552 if(m_originalCaster) // m_caster only passive source of cast
553 finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
554 else
555 finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
557 // post effects
558 switch(m_spellInfo->SpellFamilyName)
560 case SPELLFAMILY_WARRIOR:
562 // Bloodthirst
563 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
565 uint32 BTAura = 0;
566 switch(m_spellInfo->Id)
568 case 23881: BTAura = 23885; break;
569 case 23892: BTAura = 23886; break;
570 case 23893: BTAura = 23887; break;
571 case 23894: BTAura = 23888; break;
572 case 25251: BTAura = 25252; break;
573 case 30335: BTAura = 30339; break;
574 default:
575 sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
576 break;
579 if (BTAura)
580 m_caster->CastSpell(m_caster,BTAura,true);
582 break;
584 case SPELLFAMILY_PRIEST:
586 // Shadow Word: Death
587 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
588 // deals damage equal to damage done to caster if victim is not killed
589 m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
591 break;
593 case SPELLFAMILY_PALADIN:
595 // Judgement of Blood
596 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
598 int32 damagePoint = finalDamage * 33 / 100;
599 m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
601 break;
608 void Spell::EffectDummy(uint32 i)
610 if(!unitTarget && !gameObjTarget && !itemTarget)
611 return;
613 // selection by spell family
614 switch(m_spellInfo->SpellFamilyName)
616 case SPELLFAMILY_GENERIC:
617 // Gnomish Poultryizer trinket
618 switch(m_spellInfo->Id )
620 case 8063: // Deviate Fish
622 if(m_caster->GetTypeId() != TYPEID_PLAYER)
623 return;
625 uint32 spell_id = 0;
626 switch(urand(1,5))
628 case 1: spell_id = 8064; break; // Sleepy
629 case 2: spell_id = 8065; break; // Invigorate
630 case 3: spell_id = 8066; break; // Shrink
631 case 4: spell_id = 8067; break; // Party Time!
632 case 5: spell_id = 8068; break; // Healthy Spirit
634 m_caster->CastSpell(m_caster,spell_id,true,NULL);
635 return;
637 case 8213: // Savory Deviate Delight
639 if(m_caster->GetTypeId() != TYPEID_PLAYER)
640 return;
642 uint32 spell_id = 0;
643 switch(urand(1,2))
645 // Flip Out - ninja
646 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
647 // Yaaarrrr - pirate
648 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
650 m_caster->CastSpell(m_caster,spell_id,true,NULL);
651 return;
653 case 8593: // Symbol of life (restore creature to life)
654 case 31225: // Shimmering Vessel (restore creature to life)
656 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
657 return;
658 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
659 return;
661 case 12162: // Deep wounds
662 case 12850: // (now good common check for this spells)
663 case 12868:
665 if(!unitTarget)
666 return;
668 float damage;
669 // DW should benefit of attack power, damage percent mods etc.
670 // TODO: check if using offhand damage is correct and if it should be divided by 2
671 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
672 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
673 else
674 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
676 switch (m_spellInfo->Id)
678 case 12850: damage *= 0.2f; break;
679 case 12162: damage *= 0.4f; break;
680 case 12868: damage *= 0.6f; break;
681 default:
682 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
683 return;
686 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
687 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
688 return;
690 case 12975: //Last Stand
692 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
693 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
694 return;
696 case 13120: // net-o-matic
698 if(!unitTarget)
699 return;
701 uint32 spell_id = 0;
703 uint32 roll = urand(0, 99);
705 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
706 spell_id = 16566;
707 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
708 spell_id = 13119;
709 else // normal root
710 spell_id = 13099;
712 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
713 return;
715 case 13567: // Dummy Trigger
717 // can be used for different aura triggreing, so select by aura
718 if(!m_triggeredByAuraSpell || !unitTarget)
719 return;
721 switch(m_triggeredByAuraSpell->Id)
723 case 26467: // Persistent Shield
724 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
725 break;
726 default:
727 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
728 break;
730 return;
732 case 14185: // Preparation Rogue
734 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
735 return;
737 //immediately finishes the cooldown on certain Rogue abilities
738 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
739 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
741 uint32 classspell = itr->first;
742 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
744 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
746 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
748 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
749 data << uint32(classspell);
750 data << uint64(m_caster->GetGUID());
751 ((Player*)m_caster)->GetSession()->SendPacket(&data);
754 return;
756 case 15998: // Capture Worg Pup
757 case 29435: // Capture Female Kaliri Hatchling
759 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
760 return;
762 Creature* creatureTarget = (Creature*)unitTarget;
763 creatureTarget->setDeathState(JUST_DIED);
764 creatureTarget->RemoveCorpse();
765 creatureTarget->SetHealth(0); // just for nice GM-mode view
766 return;
768 case 16589: // Noggenfogger Elixir
770 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
771 return;
773 uint32 spell_id = 0;
774 switch(urand(1,3))
776 case 1: spell_id = 16595; break;
777 case 2: spell_id = 16593; break;
778 default:spell_id = 16591; break;
781 m_caster->CastSpell(m_caster,spell_id,true,NULL);
782 return;
784 case 17251: // Spirit Healer Res
786 if(!unitTarget || !m_originalCaster)
787 return;
789 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
791 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
792 data << unitTarget->GetGUID();
793 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
795 return;
797 case 17271: // Test Fetid Skull
799 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
800 return;
802 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
804 m_caster->CastSpell(m_caster,spell_id,true,NULL);
805 return;
807 case 20577: // Cannibalize
808 if (unitTarget)
809 m_caster->CastSpell(m_caster,20578,false,NULL);
810 return;
811 case 23019: // Crystal Prison Dummy DND
813 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
814 return;
816 Creature* creatureTarget = (Creature*)unitTarget;
817 if(creatureTarget->isPet())
818 return;
820 creatureTarget->setDeathState(JUST_DIED);
821 creatureTarget->RemoveCorpse();
822 creatureTarget->SetHealth(0); // just for nice GM-mode view
824 GameObject* pGameObj = new GameObject;
826 Map *map = creatureTarget->GetMap();
828 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
829 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
830 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
832 delete pGameObj;
833 return;
836 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
837 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
838 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
839 pGameObj->SetSpellId(m_spellInfo->Id);
841 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
842 map->Add(pGameObj);
844 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
845 data << uint64(pGameObj->GetGUID());
846 m_caster->SendMessageToSet(&data,true);
848 return;
850 case 23074: // Arc. Dragonling
851 if (!m_CastItem) return;
852 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
853 return;
854 case 23075: // Mithril Mechanical Dragonling
855 if (!m_CastItem) return;
856 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
857 return;
858 case 23076: // Mechanical Dragonling
859 if (!m_CastItem) return;
860 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
861 return;
862 case 23133: // Gnomish Battle Chicken
863 if (!m_CastItem) return;
864 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
865 return;
866 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
868 int32 r = irand(0, 119);
869 if ( r < 20 ) // 1/6 polymorph
870 m_caster->CastSpell(m_caster,23444,true);
871 else if ( r < 100 ) // 4/6 evil twin
872 m_caster->CastSpell(m_caster,23445,true);
873 else // 1/6 miss the target
874 m_caster->CastSpell(m_caster,36902,true);
875 return;
877 case 23453: // Ultrasafe Transporter: Gadgetzan
878 if ( roll_chance_i(50) ) // success
879 m_caster->CastSpell(m_caster,23441,true);
880 else // failure
881 m_caster->CastSpell(m_caster,23446,true);
882 return;
883 case 23645: // Hourglass Sand
884 m_caster->RemoveAurasDueToSpell(23170);
885 return;
886 case 23725: // Gift of Life (warrior bwl trinket)
887 m_caster->CastSpell(m_caster,23782,true);
888 m_caster->CastSpell(m_caster,23783,true);
889 return;
890 case 25860: // Reindeer Transformation
892 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
893 return;
895 float flyspeed = m_caster->GetSpeedRate(MOVE_FLY);
896 float speed = m_caster->GetSpeedRate(MOVE_RUN);
898 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
900 //5 different spells used depending on mounted speed and if mount can fly or not
901 if (flyspeed >= 4.1f)
902 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
903 else if (flyspeed >= 3.8f)
904 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
905 else if (flyspeed >= 1.6f)
906 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
907 else if (speed >= 2.0f)
908 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
909 else
910 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
912 return;
914 //case 26074: // Holiday Cheer
915 // return; -- implemented at client side
916 case 28006: // Arcane Cloaking
918 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
919 m_caster->CastSpell(unitTarget,29294,true);
920 return;
922 case 28730: // Arcane Torrent (Mana)
924 int32 count = 0;
925 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
926 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
927 if ((*i)->GetId() == 28734)
928 ++count;
929 if (count)
931 m_caster->RemoveAurasDueToSpell(28734);
932 int32 bp = damage * count;
933 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
935 return;
937 case 29200: // Purify Helboar Meat
939 if( m_caster->GetTypeId() != TYPEID_PLAYER )
940 return;
942 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
944 m_caster->CastSpell(m_caster,spell_id,true,NULL);
945 return;
947 case 29858: // Soulshatter
948 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
949 m_caster->CastSpell(unitTarget,32835,true);
950 return;
951 case 30458: // Nigh Invulnerability
952 if (!m_CastItem) return;
953 if(roll_chance_i(86)) // success
954 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
955 else // backfire in 14% casts
956 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
957 return;
958 case 30507: // Poultryizer
959 if (!m_CastItem) return;
960 if(roll_chance_i(80)) // success
961 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
962 else // backfire 20%
963 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
964 return;
965 case 33060: // Make a Wish
967 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
968 return;
970 uint32 spell_id = 0;
972 switch(urand(1,5))
974 case 1: spell_id = 33053; break;
975 case 2: spell_id = 33057; break;
976 case 3: spell_id = 33059; break;
977 case 4: spell_id = 33062; break;
978 case 5: spell_id = 33064; break;
981 m_caster->CastSpell(m_caster,spell_id,true,NULL);
982 return;
984 case 35745:
986 uint32 spell_id;
987 switch(m_caster->GetAreaId())
989 case 3900: spell_id = 35743; break;
990 case 3742: spell_id = 35744; break;
991 default: return;
994 m_caster->CastSpell(m_caster,spell_id,true);
995 return;
997 case 37674: // Chaos Blast
998 if(unitTarget)
999 m_caster->CastSpell(unitTarget,37675,true);
1000 return;
1001 case 44875: // Complete Raptor Capture
1003 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1004 return;
1006 Creature* creatureTarget = (Creature*)unitTarget;
1008 creatureTarget->setDeathState(JUST_DIED);
1009 creatureTarget->RemoveCorpse();
1010 creatureTarget->SetHealth(0); // just for nice GM-mode view
1012 //cast spell Raptor Capture Credit
1013 m_caster->CastSpell(m_caster,42337,true,NULL);
1014 return;
1016 case 37573: //Temporal Phase Modulator
1018 if(!unitTarget)
1019 return;
1021 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1022 if(!tempSummon)
1023 return;
1025 uint32 health = tempSummon->GetHealth();
1026 const uint32 entry_list[6] = {21821, 21820, 21817};
1028 float x = tempSummon->GetPositionX();
1029 float y = tempSummon->GetPositionY();
1030 float z = tempSummon->GetPositionZ();
1031 float o = tempSummon->GetOrientation();
1033 tempSummon->UnSummon();
1035 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1036 if (!pCreature)
1037 return;
1039 pCreature->SetHealth(health);
1041 if(pCreature->AI())
1042 pCreature->AI()->AttackStart(m_caster);
1044 return;
1046 case 34665: //Administer Antidote
1048 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1049 return;
1051 if(!unitTarget)
1052 return;
1054 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1055 if(!tempSummon)
1056 return;
1058 uint32 health = tempSummon->GetHealth();
1060 float x = tempSummon->GetPositionX();
1061 float y = tempSummon->GetPositionY();
1062 float z = tempSummon->GetPositionZ();
1063 float o = tempSummon->GetOrientation();
1064 tempSummon->UnSummon();
1066 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1067 if (!pCreature)
1068 return;
1070 pCreature->SetHealth(health);
1071 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1073 if (pCreature->AI())
1074 pCreature->AI()->AttackStart(m_caster);
1076 return;
1078 case 44997: // Converting Sentry
1080 //Converted Sentry Credit
1081 m_caster->CastSpell(m_caster, 45009, true);
1082 return;
1084 case 45030: // Impale Emissary
1086 // Emissary of Hate Credit
1087 m_caster->CastSpell(m_caster, 45088, true);
1088 return;
1090 case 50243: // Teach Language
1092 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1093 return;
1095 // spell has a 1/3 chance to trigger one of the below
1096 if(roll_chance_i(66))
1097 return;
1098 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1100 // 1000001 - gnomish binary
1101 m_caster->CastSpell(m_caster, 50242, true);
1103 else
1105 // 01001000 - goblin binary
1106 m_caster->CastSpell(m_caster, 50246, true);
1109 return;
1111 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1113 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1114 return;
1116 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1117 bg->EventPlayerDroppedFlag((Player*)m_caster);
1119 m_caster->CastSpell(m_caster, 30452, true, NULL);
1120 return;
1124 //All IconID Check in there
1125 switch(m_spellInfo->SpellIconID)
1127 // Berserking (troll racial traits)
1128 case 1661:
1130 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1131 int32 melee_mod = 10;
1132 if (healthPerc <= 40)
1133 melee_mod = 30;
1134 if (healthPerc < 100 && healthPerc > 40)
1135 melee_mod = 10+(100-healthPerc)/3;
1137 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1138 int32 hasteModBasePoints1 = (5-melee_mod);
1139 int32 hasteModBasePoints2 = 5;
1141 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1142 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1143 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1144 return;
1147 break;
1148 case SPELLFAMILY_MAGE:
1149 switch(m_spellInfo->Id )
1151 case 11958: // Cold Snap
1153 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1154 return;
1156 // immediately finishes the cooldown on Frost spells
1157 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1158 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1160 if (itr->second->state == PLAYERSPELL_REMOVED)
1161 continue;
1163 uint32 classspell = itr->first;
1164 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1166 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1167 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1168 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1170 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1172 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1173 data << uint32(classspell);
1174 data << uint64(m_caster->GetGUID());
1175 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1178 return;
1180 case 32826:
1182 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1184 //Polymorph Cast Visual Rank 1
1185 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1186 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1188 return;
1191 break;
1192 case SPELLFAMILY_WARRIOR:
1193 // Charge
1194 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
1196 int32 chargeBasePoints0 = damage;
1197 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1198 return;
1200 // Execute
1201 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1203 if(!unitTarget)
1204 return;
1206 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1207 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1208 m_caster->SetPower(POWER_RAGE,0);
1209 return;
1211 if(m_spellInfo->Id==21977) //Warrior's Wrath
1213 if(!unitTarget)
1214 return;
1216 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1217 return;
1219 break;
1220 case SPELLFAMILY_WARLOCK:
1221 //Life Tap (only it have this with dummy effect)
1222 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1224 float cost = m_currentBasePoints[0]+1;
1226 if(Player* modOwner = m_caster->GetSpellModOwner())
1227 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1229 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1231 if(int32(m_caster->GetHealth()) > dmg)
1233 // Shouldn't Appear in Combat Log
1234 m_caster->ModifyHealth(-dmg);
1236 int32 mana = dmg;
1238 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1239 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1241 // only Imp. Life Tap have this in combination with dummy aura
1242 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1243 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1246 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1248 // Mana Feed
1249 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1250 manaFeedVal = manaFeedVal * mana / 100;
1251 if(manaFeedVal > 0)
1252 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1254 else
1255 SendCastResult(SPELL_FAILED_FIZZLE);
1256 return;
1258 break;
1259 case SPELLFAMILY_PRIEST:
1260 switch(m_spellInfo->Id )
1262 case 28598: // Touch of Weakness triggered spell
1264 if(!unitTarget || !m_triggeredByAuraSpell)
1265 return;
1267 uint32 spellid = 0;
1268 switch(m_triggeredByAuraSpell->Id)
1270 case 2652: spellid = 2943; break; // Rank 1
1271 case 19261: spellid = 19249; break; // Rank 2
1272 case 19262: spellid = 19251; break; // Rank 3
1273 case 19264: spellid = 19252; break; // Rank 4
1274 case 19265: spellid = 19253; break; // Rank 5
1275 case 19266: spellid = 19254; break; // Rank 6
1276 case 25461: spellid = 25460; break; // Rank 7
1277 default:
1278 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1279 return;
1281 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1282 return;
1285 break;
1286 case SPELLFAMILY_DRUID:
1287 switch(m_spellInfo->Id )
1289 case 5420: // Tree of Life passive
1291 // Tree of Life area effect
1292 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1293 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1294 return;
1297 break;
1298 case SPELLFAMILY_ROGUE:
1299 switch(m_spellInfo->Id )
1301 case 31231: // Cheat Death
1303 m_caster->CastSpell(m_caster,45182,true);
1304 return;
1306 case 5938: // Shiv
1308 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1309 return;
1311 Player *pCaster = ((Player*)m_caster);
1313 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1314 if(!item)
1315 return;
1317 // all poison enchantments is temporary
1318 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1319 if(!enchant_id)
1320 return;
1322 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1323 if(!pEnchant)
1324 return;
1326 for (int s=0;s<3;s++)
1328 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1329 continue;
1331 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1332 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1333 continue;
1335 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1338 m_caster->CastSpell(unitTarget, 5940, true);
1339 return;
1342 break;
1343 case SPELLFAMILY_HUNTER:
1344 // Steady Shot
1345 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1347 if( !unitTarget || !unitTarget->isAlive())
1348 return;
1350 bool found = false;
1352 // check dazed affect
1353 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1354 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1356 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1358 found = true;
1359 break;
1363 if(found)
1364 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
1365 return;
1367 // Kill command
1368 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1370 if(m_caster->getClass()!=CLASS_HUNTER)
1371 return;
1373 // clear hunter crit aura state
1374 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1376 // additional damage from pet to pet target
1377 Pet* pet = m_caster->GetPet();
1378 if(!pet || !pet->getVictim())
1379 return;
1381 uint32 spell_id = 0;
1382 switch (m_spellInfo->Id)
1384 case 34026: spell_id = 34027; break; // rank 1
1385 default:
1386 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1387 return;
1390 pet->CastSpell(pet->getVictim(), spell_id, true);
1391 return;
1394 switch(m_spellInfo->Id)
1396 case 23989: //Readiness talent
1398 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1399 return;
1401 //immediately finishes the cooldown for hunter abilities
1402 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1403 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1405 uint32 classspell = itr->first;
1406 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1408 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1410 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1412 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1413 data << uint32(classspell);
1414 data << uint64(m_caster->GetGUID());
1415 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1418 return;
1420 case 37506: // Scatter Shot
1422 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1423 return;
1425 // break Auto Shot and autohit
1426 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1427 m_caster->AttackStop();
1428 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1429 return;
1432 break;
1433 case SPELLFAMILY_PALADIN:
1434 switch(m_spellInfo->SpellIconID)
1436 case 156: // Holy Shock
1438 if(!unitTarget)
1439 return;
1441 int hurt = 0;
1442 int heal = 0;
1444 switch(m_spellInfo->Id)
1446 case 20473: hurt = 25912; heal = 25914; break;
1447 case 20929: hurt = 25911; heal = 25913; break;
1448 case 20930: hurt = 25902; heal = 25903; break;
1449 case 27174: hurt = 27176; heal = 27175; break;
1450 case 33072: hurt = 33073; heal = 33074; break;
1451 default:
1452 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1453 return;
1456 if(m_caster->IsFriendlyTo(unitTarget))
1457 m_caster->CastSpell(unitTarget, heal, true, 0);
1458 else
1459 m_caster->CastSpell(unitTarget, hurt, true, 0);
1461 return;
1463 case 561: // Judgement of command
1465 if(!unitTarget)
1466 return;
1468 uint32 spell_id = m_currentBasePoints[i]+1;
1469 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1470 if(!spell_proto)
1471 return;
1473 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1475 // decreased damage (/2) for non-stunned target.
1476 SpellModifier *mod = new SpellModifier;
1477 mod->op = SPELLMOD_DAMAGE;
1478 mod->value = -50;
1479 mod->type = SPELLMOD_PCT;
1480 mod->spellId = m_spellInfo->Id;
1481 mod->effectId = i;
1482 mod->lastAffected = NULL;
1483 mod->mask = 0x0000020000000000LL;
1484 mod->charges = 0;
1486 ((Player*)m_caster)->AddSpellMod(mod, true);
1487 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1488 // mod deleted
1489 ((Player*)m_caster)->AddSpellMod(mod, false);
1491 else
1492 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1494 return;
1498 switch(m_spellInfo->Id)
1500 case 31789: // Righteous Defense (step 1)
1502 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1504 // non-standard cast requirement check
1505 if (!unitTarget || unitTarget->getAttackers().empty())
1507 // clear cooldown at fail
1508 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1510 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1512 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1513 data << uint32(m_spellInfo->Id);
1514 data << uint64(m_caster->GetGUID());
1515 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1518 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1519 return;
1522 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1523 // Clear targets for eff 1
1524 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1525 ihit->effectMask &= ~(1<<1);
1527 // not empty (checked)
1528 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1530 // chance to be selected from list
1531 float chance = 100.0f/attackers.size();
1532 uint32 count=0;
1533 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1535 if(!roll_chance_f(chance))
1536 continue;
1537 ++count;
1538 AddUnitTarget((*aItr), 1);
1541 // now let next effect cast spell at each target.
1542 return;
1544 case 37877: // Blessing of Faith
1546 if(!unitTarget)
1547 return;
1549 uint32 spell_id = 0;
1550 switch(unitTarget->getClass())
1552 case CLASS_DRUID: spell_id = 37878; break;
1553 case CLASS_PALADIN: spell_id = 37879; break;
1554 case CLASS_PRIEST: spell_id = 37880; break;
1555 case CLASS_SHAMAN: spell_id = 37881; break;
1556 default: return; // ignore for not healing classes
1559 m_caster->CastSpell(m_caster,spell_id,true);
1560 return;
1563 break;
1564 case SPELLFAMILY_SHAMAN:
1565 //Shaman Rockbiter Weapon
1566 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1568 uint32 spell_id = 0;
1569 switch(m_spellInfo->Id)
1571 case 8017: spell_id = 36494; break; // Rank 1
1572 case 8018: spell_id = 36750; break; // Rank 2
1573 case 8019: spell_id = 36755; break; // Rank 3
1574 case 10399: spell_id = 36759; break; // Rank 4
1575 case 16314: spell_id = 36763; break; // Rank 5
1576 case 16315: spell_id = 36766; break; // Rank 6
1577 case 16316: spell_id = 36771; break; // Rank 7
1578 case 25479: spell_id = 36775; break; // Rank 8
1579 case 25485: spell_id = 36499; break; // Rank 9
1580 default:
1581 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1582 return;
1585 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1587 if(!spellInfo)
1589 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1590 return;
1593 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1594 return;
1596 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1598 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1600 if(item->IsFitToSpellRequirements(m_spellInfo))
1602 Spell *spell = new Spell(m_caster, spellInfo, true);
1604 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1605 // at calculation applied affect from Elemental Weapons talent
1606 // real enchantment damage-1
1607 spell->m_currentBasePoints[1] = damage-1;
1609 SpellCastTargets targets;
1610 targets.setItemTarget( item );
1611 spell->prepare(&targets);
1615 return;
1618 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1620 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1621 return;
1623 // Regenerate 6% of Total Mana Every 3 secs
1624 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1625 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1626 return;
1629 break;
1632 // pet auras
1633 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1635 m_caster->AddPetAura(petSpell);
1636 return;
1640 void Spell::EffectTriggerSpellWithValue(uint32 i)
1642 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1644 // normal case
1645 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1647 if(!spellInfo)
1649 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1650 return;
1653 int32 bp = damage;
1654 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1657 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1659 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1660 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1662 if(!spellInfo)
1664 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1665 return;
1668 finish();
1669 Spell *spell = new Spell(m_caster, spellInfo, true);
1671 SpellCastTargets targets;
1672 targets.setUnitTarget( unitTarget);
1673 spell->prepare(&targets);
1675 m_caster->SetCurrentCastedSpell(spell);
1676 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1680 void Spell::EffectForceCast(uint32 i)
1682 if( !unitTarget )
1683 return;
1685 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1687 // normal case
1688 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1690 if(!spellInfo)
1692 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1693 return;
1696 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1699 void Spell::EffectTriggerSpell(uint32 i)
1701 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1703 // special cases
1704 switch(triggered_spell_id)
1706 // Vanish
1707 case 18461:
1709 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1710 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1711 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1713 // if this spell is given to NPC it must handle rest by it's own AI
1714 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1715 return;
1717 // get highest rank of the Stealth spell
1718 uint32 spellId = 0;
1719 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1720 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1722 // only highest rank is shown in spell book, so simply check if shown in spell book
1723 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1724 continue;
1726 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1727 if (!spellInfo)
1728 continue;
1730 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1732 spellId = spellInfo->Id;
1733 break;
1737 // no Stealth spell found
1738 if (!spellId)
1739 return;
1741 // reset cooldown on it if needed
1742 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1743 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1745 m_caster->CastSpell(m_caster, spellId, true);
1746 return;
1748 // just skip
1749 case 23770: // Sayge's Dark Fortune of *
1750 // not exist, common cooldown can be implemented in scripts if need.
1751 return;
1752 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1753 case 29284:
1755 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1756 if (!spell)
1757 return;
1759 for (int i=0; i < spell->StackAmount; ++i)
1760 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1761 return;
1763 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1764 case 29286:
1766 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1767 if (!spell)
1768 return;
1770 for (int i=0; i < spell->StackAmount; ++i)
1771 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1772 return;
1774 // Righteous Defense
1775 case 31980:
1777 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1778 return;
1780 // Cloak of Shadows
1781 case 35729 :
1783 Unit::AuraMap& Auras = m_caster->GetAuras();
1784 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1786 // remove all harmful spells on you...
1787 if( // ignore positive and passive auras
1788 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1789 // ignore physical auras
1790 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1791 // ignore immunity persistent spells
1792 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1794 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1795 iter = Auras.begin();
1798 return;
1800 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1801 case 41967:
1803 if (Unit *pet = m_caster->GetPet())
1804 pet->CastSpell(pet, 28305, true);
1805 return;
1809 // normal case
1810 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1812 if(!spellInfo)
1814 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1815 return;
1818 // some triggered spells require specific equipment
1819 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1821 // main hand weapon required
1822 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1824 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1826 // skip spell if no weapon in slot or broken
1827 if(!item || item->IsBroken() )
1828 return;
1830 // skip spell if weapon not fit to triggered spell
1831 if(!item->IsFitToSpellRequirements(spellInfo))
1832 return;
1835 // offhand hand weapon required
1836 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1838 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1840 // skip spell if no weapon in slot or broken
1841 if(!item || item->IsBroken() )
1842 return;
1844 // skip spell if weapon not fit to triggered spell
1845 if(!item->IsFitToSpellRequirements(spellInfo))
1846 return;
1850 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1851 bool instant = false;
1852 for(uint32 j = i+1; j < 3; ++j)
1854 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1856 instant = true;
1857 break;
1861 if(instant)
1863 if (unitTarget)
1864 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1866 else
1867 m_TriggerSpells.push_back(spellInfo);
1870 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1872 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1874 // normal case
1875 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1877 if(!spellInfo)
1879 sLog.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id);
1880 return;
1883 if (m_CastItem)
1884 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1886 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1888 SpellCastTargets targets;
1889 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1890 spell->m_CastItem = m_CastItem;
1891 spell->prepare(&targets, NULL);
1894 void Spell::EffectTeleportUnits(uint32 i)
1896 if(!unitTarget || unitTarget->isInFlight())
1897 return;
1899 switch (m_spellInfo->EffectImplicitTargetB[i])
1901 case TARGET_INNKEEPER_COORDINATES:
1903 // Only players can teleport to innkeeper
1904 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1905 return;
1907 ((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);
1908 return;
1910 case TARGET_TABLE_X_Y_Z_COORDINATES:
1912 // TODO: Only players can teleport?
1913 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1914 return;
1915 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1916 if(!st)
1918 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1919 return;
1921 ((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);
1922 break;
1924 case TARGET_BEHIND_VICTIM:
1926 // Get selected target for player (or victim for units)
1927 Unit *pTarget = NULL;
1928 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1929 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1930 else
1931 pTarget = m_caster->getVictim();
1932 // No target present - return
1933 if (!pTarget)
1934 return;
1935 // Init dest coordinates
1936 uint32 mapid = m_caster->GetMapId();
1937 float x = m_targets.m_destX;
1938 float y = m_targets.m_destY;
1939 float z = m_targets.m_destZ;
1940 float orientation = pTarget->GetOrientation();
1941 // Teleport
1942 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1943 ((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));
1944 else
1946 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1947 WorldPacket data;
1948 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1949 unitTarget->SendMessageToSet(&data, false);
1951 return;
1953 default:
1955 // If not exist data for dest location - return
1956 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
1958 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
1959 return;
1961 // Init dest coordinates
1962 uint32 mapid = m_caster->GetMapId();
1963 float x = m_targets.m_destX;
1964 float y = m_targets.m_destY;
1965 float z = m_targets.m_destZ;
1966 float orientation = unitTarget->GetOrientation();
1967 // Teleport
1968 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1969 ((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));
1970 else
1972 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1973 WorldPacket data;
1974 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1975 unitTarget->SendMessageToSet(&data, false);
1977 return;
1981 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1982 switch ( m_spellInfo->Id )
1984 // Dimensional Ripper - Everlook
1985 case 23442:
1987 int32 r = irand(0, 119);
1988 if ( r >= 70 ) // 7/12 success
1990 if ( r < 100 ) // 4/12 evil twin
1991 m_caster->CastSpell(m_caster,23445,true);
1992 else // 1/12 fire
1993 m_caster->CastSpell(m_caster,23449,true);
1995 return;
1997 // Ultrasafe Transporter: Toshley's Station
1998 case 36941:
2000 if ( roll_chance_i(50) ) // 50% success
2002 int32 rand_eff = urand(1,7);
2003 switch ( rand_eff )
2005 case 1:
2006 // soul split - evil
2007 m_caster->CastSpell(m_caster,36900,true);
2008 break;
2009 case 2:
2010 // soul split - good
2011 m_caster->CastSpell(m_caster,36901,true);
2012 break;
2013 case 3:
2014 // Increase the size
2015 m_caster->CastSpell(m_caster,36895,true);
2016 break;
2017 case 4:
2018 // Decrease the size
2019 m_caster->CastSpell(m_caster,36893,true);
2020 break;
2021 case 5:
2022 // Transform
2024 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2025 m_caster->CastSpell(m_caster,36897,true);
2026 else
2027 m_caster->CastSpell(m_caster,36899,true);
2028 break;
2030 case 6:
2031 // chicken
2032 m_caster->CastSpell(m_caster,36940,true);
2033 break;
2034 case 7:
2035 // evil twin
2036 m_caster->CastSpell(m_caster,23445,true);
2037 break;
2040 return;
2042 // Dimensional Ripper - Area 52
2043 case 36890:
2045 if ( roll_chance_i(50) ) // 50% success
2047 int32 rand_eff = urand(1,4);
2048 switch ( rand_eff )
2050 case 1:
2051 // soul split - evil
2052 m_caster->CastSpell(m_caster,36900,true);
2053 break;
2054 case 2:
2055 // soul split - good
2056 m_caster->CastSpell(m_caster,36901,true);
2057 break;
2058 case 3:
2059 // Increase the size
2060 m_caster->CastSpell(m_caster,36895,true);
2061 break;
2062 case 4:
2063 // Transform
2065 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2066 m_caster->CastSpell(m_caster,36897,true);
2067 else
2068 m_caster->CastSpell(m_caster,36899,true);
2069 break;
2073 return;
2078 void Spell::EffectApplyAura(uint32 i)
2080 if(!unitTarget)
2081 return;
2083 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2084 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2085 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2086 return;
2088 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2089 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2090 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2091 return;
2093 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2094 if(!caster)
2095 return;
2097 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2099 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2101 // Now Reduce spell duration using data received at spell hit
2102 int32 duration = Aur->GetAuraMaxDuration();
2103 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2104 Aur->setDiminishGroup(m_diminishGroup);
2106 // if Aura removed and deleted, do not continue.
2107 if(duration== 0 && !(Aur->IsPermanent()))
2109 delete Aur;
2110 return;
2113 if(duration != Aur->GetAuraMaxDuration())
2115 Aur->SetAuraMaxDuration(duration);
2116 Aur->SetAuraDuration(duration);
2119 bool added = unitTarget->AddAura(Aur);
2121 // Aura not added and deleted in AddAura call;
2122 if (!added)
2123 return;
2125 // found crash at character loading, broken pointer to Aur...
2126 // Aur was deleted in AddAura()...
2127 if(!Aur)
2128 return;
2130 // TODO Make a way so it works for every related spell!
2131 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2133 uint32 spellId = 0;
2134 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2135 spellId = 6788; // Weakened Soul
2136 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2137 spellId = 25771; // Forbearance
2138 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2139 spellId = 41425; // Hypothermia
2140 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2141 spellId = 11196; // Recently Bandaged
2142 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2143 spellId = 23230; // Blood Fury - Healing Reduction
2145 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2146 if (AdditionalSpellInfo)
2148 // applied at target by target
2149 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2150 unitTarget->AddAura(AdditionalAura);
2151 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2155 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2156 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2157 m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
2160 void Spell::EffectUnlearnSpecialization( uint32 i )
2162 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2163 return;
2165 Player *_player = (Player*)unitTarget;
2166 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2168 _player->removeSpell(spellToUnlearn);
2170 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2173 void Spell::EffectPowerDrain(uint32 i)
2175 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2176 return;
2178 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2180 if(!unitTarget)
2181 return;
2182 if(!unitTarget->isAlive())
2183 return;
2184 if(unitTarget->getPowerType() != drain_power)
2185 return;
2186 if(damage < 0)
2187 return;
2189 uint32 curPower = unitTarget->GetPower(drain_power);
2191 //add spell damage bonus
2192 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2194 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2195 uint32 power = damage;
2196 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2197 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2199 int32 new_damage;
2200 if(curPower < power)
2201 new_damage = curPower;
2202 else
2203 new_damage = power;
2205 unitTarget->ModifyPower(drain_power,-new_damage);
2207 if(drain_power == POWER_MANA)
2209 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2210 if(manaMultiplier==0)
2211 manaMultiplier = 1;
2213 if(Player *modOwner = m_caster->GetSpellModOwner())
2214 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2216 int32 gain = int32(new_damage*manaMultiplier);
2218 m_caster->ModifyPower(POWER_MANA,gain);
2219 //send log
2220 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false);
2224 void Spell::EffectSendEvent(uint32 EffectIndex)
2226 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2228 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2229 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2231 switch(m_spellInfo->Id)
2233 case 23333: // Pickup Horde Flag
2234 /*do not uncomment .
2235 if(bg->GetTypeID()==BATTLEGROUND_WS)
2236 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2237 sLog.outDebug("Send Event Horde Flag Picked Up");
2238 break;
2239 /* not used :
2240 case 23334: // Drop Horde Flag
2241 if(bg->GetTypeID()==BATTLEGROUND_WS)
2242 bg->EventPlayerDroppedFlag((Player*)m_caster);
2243 sLog.outDebug("Drop Horde Flag");
2244 break;
2246 case 23335: // Pickup Alliance Flag
2247 /*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
2248 if(bg->GetTypeID()==BATTLEGROUND_WS)
2249 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2250 sLog.outDebug("Send Event Alliance Flag Picked Up");
2251 break;
2252 /* not used :
2253 case 23336: // Drop Alliance Flag
2254 if(bg->GetTypeID()==BATTLEGROUND_WS)
2255 bg->EventPlayerDroppedFlag((Player*)m_caster);
2256 sLog.outDebug("Drop Alliance Flag");
2257 break;
2258 case 23385: // Alliance Flag Returns
2259 if(bg->GetTypeID()==BATTLEGROUND_WS)
2260 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2261 sLog.outDebug("Alliance Flag Returned");
2262 break;
2263 case 23386: // Horde Flag Returns
2264 if(bg->GetTypeID()==BATTLEGROUND_WS)
2265 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2266 sLog.outDebug("Horde Flag Returned");
2267 break;*/
2268 case 34976:
2270 if(bg->GetTypeID()==BATTLEGROUND_EY)
2271 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2273 break;
2274 default:
2275 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2276 break;
2280 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2281 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2284 void Spell::EffectPowerBurn(uint32 i)
2286 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2287 return;
2289 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2291 if(!unitTarget)
2292 return;
2293 if(!unitTarget->isAlive())
2294 return;
2295 if(unitTarget->getPowerType()!=powertype)
2296 return;
2297 if(damage < 0)
2298 return;
2300 int32 curPower = int32(unitTarget->GetPower(powertype));
2302 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2303 uint32 power = damage;
2304 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2305 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2307 int32 new_damage = (curPower < power) ? curPower : power;
2309 unitTarget->ModifyPower(powertype,-new_damage);
2310 float multiplier = m_spellInfo->EffectMultipleValue[i];
2312 if(Player *modOwner = m_caster->GetSpellModOwner())
2313 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2315 new_damage = int32(new_damage*multiplier);
2316 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2319 void Spell::EffectHeal( uint32 /*i*/ )
2321 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2323 // Try to get original caster
2324 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2326 // Skip if m_originalCaster not available
2327 if (!caster)
2328 return;
2330 int32 addhealth = damage;
2332 // Vessel of the Naaru (Vial of the Sunwell trinket)
2333 if (m_spellInfo->Id == 45064)
2335 // Amount of heal - depends from stacked Holy Energy
2336 int damageAmount = 0;
2337 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2338 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2339 if((*i)->GetId() == 45062)
2340 damageAmount+=(*i)->GetModifier()->m_amount;
2341 if (damageAmount)
2342 m_caster->RemoveAurasDueToSpell(45062);
2344 addhealth += damageAmount;
2346 // Swiftmend - consumes Regrowth or Rejuvenation
2347 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2349 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2350 // find most short by duration
2351 Aura *targetAura = NULL;
2352 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2354 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2355 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2357 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2358 targetAura = *i;
2362 if(!targetAura)
2364 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2365 return;
2367 int idx = 0;
2368 while(idx < 3)
2370 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2371 break;
2372 idx++;
2375 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2376 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2377 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2379 addhealth += tickheal * tickcount;
2381 else
2382 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2384 bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
2385 if (crit)
2386 addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
2387 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
2389 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2390 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2392 if(caster->GetTypeId()==TYPEID_PLAYER)
2393 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2394 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2396 // ignore item heals
2397 if(m_CastItem)
2398 return;
2400 uint32 procHealer = PROC_FLAG_HEAL;
2401 if (crit)
2402 procHealer |= PROC_FLAG_CRIT_HEAL;
2404 m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
2408 void Spell::EffectHealPct( uint32 /*i*/ )
2410 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2412 // Try to get original caster
2413 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2415 // Skip if m_originalCaster not available
2416 if (!caster)
2417 return;
2419 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2420 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2422 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2423 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2425 if(caster->GetTypeId()==TYPEID_PLAYER)
2426 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2427 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2431 void Spell::EffectHealMechanical( uint32 /*i*/ )
2433 // Mechanic creature type should be correctly checked by targetCreatureType field
2434 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2436 // Try to get original caster
2437 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2439 // Skip if m_originalCaster not available
2440 if (!caster)
2441 return;
2443 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2444 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2445 unitTarget->ModifyHealth( int32(damage) );
2449 void Spell::EffectHealthLeech(uint32 i)
2451 if(!unitTarget)
2452 return;
2453 if(!unitTarget->isAlive())
2454 return;
2456 if(damage < 0)
2457 return;
2459 sLog.outDebug("HealthLeech :%i", damage);
2461 float multiplier = m_spellInfo->EffectMultipleValue[i];
2463 if(Player *modOwner = m_caster->GetSpellModOwner())
2464 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2466 int32 new_damage = int32(damage*multiplier);
2467 uint32 curHealth = unitTarget->GetHealth();
2468 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2469 if(curHealth < new_damage)
2470 new_damage = curHealth;
2472 if(m_caster->isAlive())
2474 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2476 m_caster->ModifyHealth(new_damage);
2478 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2479 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2483 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2485 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2486 return;
2488 Player* player = (Player*)unitTarget;
2490 uint32 newitemid = itemtype;
2491 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2492 if(!pProto)
2494 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2495 return;
2498 uint32 num_to_add;
2500 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2501 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2503 int32 basePoints = m_currentBasePoints[i];
2504 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2505 if (randomPoints)
2506 num_to_add = basePoints + irand(1, randomPoints);
2507 else
2508 num_to_add = basePoints + 1;
2510 else if (pProto->MaxCount == 1)
2511 num_to_add = 1;
2512 else if(player->getLevel() >= m_spellInfo->spellLevel)
2514 int32 basePoints = m_currentBasePoints[i];
2515 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2516 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2518 else
2519 num_to_add = 2;
2521 if (num_to_add < 1)
2522 num_to_add = 1;
2523 if (num_to_add > pProto->Stackable)
2524 num_to_add = pProto->Stackable;
2526 // init items_count to 1, since 1 item will be created regardless of specialization
2527 int items_count=1;
2528 // the chance to create additional items
2529 float additionalCreateChance=0.0f;
2530 // the maximum number of created additional items
2531 uint8 additionalMaxNum=0;
2532 // get the chance and maximum number for creating extra items
2533 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2535 // roll with this chance till we roll not to create or we create the max num
2536 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2537 ++items_count;
2540 // really will be created more items
2541 num_to_add *= items_count;
2543 // can the player store the new item?
2544 ItemPosCountVec dest;
2545 uint32 no_space = 0;
2546 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2547 if( msg != EQUIP_ERR_OK )
2549 // convert to possible store amount
2550 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2551 num_to_add -= no_space;
2552 else
2554 // if not created by another reason from full inventory or unique items amount limitation
2555 player->SendEquipError( msg, NULL, NULL );
2556 return;
2560 if(num_to_add)
2562 // create the new item and store it
2563 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2565 // was it successful? return error if not
2566 if(!pItem)
2568 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2569 return;
2572 // set the "Crafted by ..." property of the item
2573 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2574 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2576 // send info to the client
2577 if(pItem)
2578 player->SendNewItem(pItem, num_to_add, true, true);
2580 // we succeeded in creating at least one item, so a levelup is possible
2581 player->UpdateCraftSkill(m_spellInfo->Id);
2584 // for battleground marks send by mail if not add all expected
2585 if(no_space > 0 )
2587 BattleGroundTypeId bgType;
2588 switch(m_spellInfo->Id)
2590 case SPELL_AV_MARK_WINNER:
2591 case SPELL_AV_MARK_LOSER:
2592 bgType = BATTLEGROUND_AV;
2593 break;
2594 case SPELL_WS_MARK_WINNER:
2595 case SPELL_WS_MARK_LOSER:
2596 bgType = BATTLEGROUND_WS;
2597 break;
2598 case SPELL_AB_MARK_WINNER:
2599 case SPELL_AB_MARK_LOSER:
2600 bgType = BATTLEGROUND_AB;
2601 break;
2602 default:
2603 return;
2606 if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
2607 bg->SendRewardMarkByMail(player,newitemid,no_space);
2611 void Spell::EffectCreateItem(uint32 i)
2613 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2616 void Spell::EffectPersistentAA(uint32 i)
2618 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2620 if(Player* modOwner = m_caster->GetSpellModOwner())
2621 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2623 int32 duration = GetSpellDuration(m_spellInfo);
2624 DynamicObject* dynObj = new DynamicObject;
2625 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))
2627 delete dynObj;
2628 return;
2630 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2631 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2632 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2633 m_caster->AddDynObject(dynObj);
2634 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
2637 void Spell::EffectEnergize(uint32 i)
2639 if(!unitTarget)
2640 return;
2641 if(!unitTarget->isAlive())
2642 return;
2644 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2645 return;
2647 // Some level depends spells
2648 int multipler = 0;
2649 int level_diff = 0;
2650 switch (m_spellInfo->Id)
2652 // Restore Energy
2653 case 9512:
2654 level_diff = m_caster->getLevel() - 40;
2655 multipler = 2;
2656 break;
2657 // Blood Fury
2658 case 24571:
2659 level_diff = m_caster->getLevel() - 60;
2660 multipler = 10;
2661 break;
2662 // Burst of Energy
2663 case 24532:
2664 level_diff = m_caster->getLevel() - 60;
2665 multipler = 4;
2666 break;
2667 default:
2668 break;
2671 if (level_diff > 0)
2672 damage -= multipler * level_diff;
2674 if(damage < 0)
2675 return;
2677 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2679 if(unitTarget->GetMaxPower(power) == 0)
2680 return;
2682 unitTarget->ModifyPower(power,damage);
2683 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2685 // Mad Alchemist's Potion
2686 if (m_spellInfo->Id == 45051)
2688 // find elixirs on target
2689 uint32 elixir_mask = 0;
2690 Unit::AuraMap& Auras = unitTarget->GetAuras();
2691 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2693 uint32 spell_id = itr->second->GetId();
2694 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2695 elixir_mask |= mask;
2698 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2699 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2701 // get all available elixirs by mask and spell level
2702 std::vector<uint32> elixirs;
2703 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2704 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2706 if (itr->second & elixir_mask)
2708 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2709 continue;
2711 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2712 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2713 continue;
2715 elixirs.push_back(itr->first);
2719 if (!elixirs.empty())
2721 // cast random elixir on target
2722 uint32 rand_spell = urand(0,elixirs.size()-1);
2723 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2728 void Spell::EffectEnergisePct(uint32 i)
2730 if(!unitTarget)
2731 return;
2732 if(!unitTarget->isAlive())
2733 return;
2735 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2736 return;
2738 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2740 uint32 maxPower = unitTarget->GetMaxPower(power);
2741 if(maxPower == 0)
2742 return;
2744 uint32 gain = damage * maxPower / 100;
2745 unitTarget->ModifyPower(power, gain);
2746 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2749 void Spell::SendLoot(uint64 guid, LootType loottype)
2751 Player* player = (Player*)m_caster;
2752 if (!player)
2753 return;
2755 if (gameObjTarget)
2757 switch (gameObjTarget->GetGoType())
2759 case GAMEOBJECT_TYPE_DOOR:
2760 case GAMEOBJECT_TYPE_BUTTON:
2761 gameObjTarget->UseDoorOrButton();
2762 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2763 return;
2765 case GAMEOBJECT_TYPE_QUESTGIVER:
2766 // start or end quest
2767 player->PrepareQuestMenu(guid);
2768 player->SendPreparedQuest(guid);
2769 return;
2771 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2772 // triggering linked GO
2773 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2774 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2775 return;
2777 case GAMEOBJECT_TYPE_GOOBER:
2778 // goober_scripts can be triggered if the player don't have the quest
2779 if (gameObjTarget->GetGOInfo()->goober.eventId)
2781 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2782 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2785 // cast goober spell
2786 if (gameObjTarget->GetGOInfo()->goober.questId)
2787 ///Quest require to be active for GO using
2788 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2789 return;
2791 gameObjTarget->AddUniqueUse(player);
2792 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2794 //TODO? Objective counting called without spell check but with quest objective check
2795 // if send spell id then this line will duplicate to spell casting call (double counting)
2796 // So we or have this line and not required in quest_template have reqSpellIdN
2797 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2798 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2800 // triggering linked GO
2801 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2802 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2804 return;
2806 case GAMEOBJECT_TYPE_CHEST:
2807 // TODO: possible must be moved to loot release (in different from linked triggering)
2808 if (gameObjTarget->GetGOInfo()->chest.eventId)
2810 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2811 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2814 // triggering linked GO
2815 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2816 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2818 // Don't return, let loots been taken
2822 // Send loot
2823 player->SendLoot(guid, loottype);
2826 void Spell::EffectOpenLock(uint32 /*i*/)
2828 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2830 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2831 return;
2834 Player* player = (Player*)m_caster;
2836 LootType loottype = LOOT_CORPSE;
2837 uint32 lockId = 0;
2838 uint64 guid = 0;
2840 // Get lockId
2841 if(gameObjTarget)
2843 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2844 // Arathi Basin banner opening !
2845 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2846 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2848 //isAllowUseBattleGroundObject() already called in CanCast()
2849 // in battleground check
2850 if(BattleGround *bg = player->GetBattleGround())
2852 // check if it's correct bg
2853 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2854 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2855 return;
2858 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2860 //isAllowUseBattleGroundObject() already called in CanCast()
2861 // in battleground check
2862 if(BattleGround *bg = player->GetBattleGround())
2864 if(bg->GetTypeID() == BATTLEGROUND_EY)
2865 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2866 return;
2869 lockId = gameObjTarget->GetLockId();
2870 guid = gameObjTarget->GetGUID();
2872 else if(itemTarget)
2874 lockId = itemTarget->GetProto()->LockID;
2875 guid = itemTarget->GetGUID();
2877 else
2879 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2880 return;
2883 if(!lockId) // possible case for GO and maybe for items.
2885 SendLoot(guid, loottype);
2886 return;
2889 // Get LockInfo
2890 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2892 if (!lockInfo)
2894 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2895 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2896 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2897 return;
2900 // check key
2901 for(int i = 0; i < 8; ++i)
2903 // Type==1 This means lockInfo->Index[i] is an item
2904 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2906 SendLoot(guid, loottype);
2907 return;
2911 uint32 SkillId = 0;
2912 // Check and skill-up skill
2913 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2914 SkillId = m_spellInfo->EffectMiscValue[1];
2915 // pickpocketing spells
2916 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2917 SkillId = SKILL_LOCKPICKING;
2919 // skill bonus provided by casting spell (mostly item spells)
2920 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2922 uint32 reqSkillValue = lockInfo->Skill[0];
2924 if(lockInfo->Skill[1]) // required pick lock skill applying
2926 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2928 SendCastResult(SPELL_FAILED_FIZZLE);
2929 return;
2932 reqSkillValue = lockInfo->Skill[1];
2934 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2936 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2937 return;
2940 if ( SkillId )
2942 loottype = LOOT_SKINNING;
2943 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2945 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2946 return;
2949 // update skill if really known
2950 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2951 if(SkillValue) // non only item base skill
2953 if(gameObjTarget)
2955 // Allow one skill-up until respawned
2956 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
2957 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
2958 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
2960 else if(itemTarget)
2962 // Do one skill-up
2963 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2964 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
2969 SendLoot(guid, loottype);
2972 void Spell::EffectSummonChangeItem(uint32 i)
2974 if(m_caster->GetTypeId() != TYPEID_PLAYER)
2975 return;
2977 Player *player = (Player*)m_caster;
2979 // applied only to using item
2980 if(!m_CastItem)
2981 return;
2983 // ... only to item in own inventory/bank/equip_slot
2984 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
2985 return;
2987 uint32 newitemid = m_spellInfo->EffectItemType[i];
2988 if(!newitemid)
2989 return;
2991 uint16 pos = m_CastItem->GetPos();
2993 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
2994 if( !pNewItem )
2995 return;
2997 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
2999 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3000 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3003 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3005 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3006 player->DurabilityLoss(pNewItem, loosePercent);
3009 if( player->IsInventoryPos( pos ) )
3011 ItemPosCountVec dest;
3012 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3013 if( msg == EQUIP_ERR_OK )
3015 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3017 // prevent crash at access and unexpected charges counting with item update queue corrupt
3018 if(m_CastItem==m_targets.getItemTarget())
3019 m_targets.setItemTarget(NULL);
3021 m_CastItem = NULL;
3023 player->StoreItem( dest, pNewItem, true);
3024 return;
3027 else if( player->IsBankPos ( pos ) )
3029 ItemPosCountVec dest;
3030 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3031 if( msg == EQUIP_ERR_OK )
3033 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3035 // prevent crash at access and unexpected charges counting with item update queue corrupt
3036 if(m_CastItem==m_targets.getItemTarget())
3037 m_targets.setItemTarget(NULL);
3039 m_CastItem = NULL;
3041 player->BankItem( dest, pNewItem, true);
3042 return;
3045 else if( player->IsEquipmentPos ( pos ) )
3047 uint16 dest;
3048 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3049 if( msg == EQUIP_ERR_OK )
3051 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3053 // prevent crash at access and unexpected charges counting with item update queue corrupt
3054 if(m_CastItem==m_targets.getItemTarget())
3055 m_targets.setItemTarget(NULL);
3057 m_CastItem = NULL;
3059 player->EquipItem( dest, pNewItem, true);
3060 player->AutoUnequipOffhandIfNeed();
3061 return;
3065 // fail
3066 delete pNewItem;
3069 void Spell::EffectOpenSecretSafe(uint32 i)
3071 EffectOpenLock(i); //no difference for now
3074 void Spell::EffectProficiency(uint32 /*i*/)
3076 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3077 return;
3078 Player *p_target = (Player*)unitTarget;
3080 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3081 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3083 p_target->AddWeaponProficiency(subClassMask);
3084 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3086 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3088 p_target->AddArmorProficiency(subClassMask);
3089 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3093 void Spell::EffectApplyAreaAura(uint32 i)
3095 if(!unitTarget)
3096 return;
3097 if(!unitTarget->isAlive())
3098 return;
3100 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3101 unitTarget->AddAura(Aur);
3104 void Spell::EffectSummonType(uint32 i)
3106 switch(m_spellInfo->EffectMiscValueB[i])
3108 case SUMMON_TYPE_GUARDIAN:
3109 case SUMMON_TYPE_POSESSED:
3110 case SUMMON_TYPE_POSESSED2:
3111 EffectSummonGuardian(i);
3112 break;
3113 case SUMMON_TYPE_WILD:
3114 EffectSummonWild(i);
3115 break;
3116 case SUMMON_TYPE_DEMON:
3117 EffectSummonDemon(i);
3118 break;
3119 case SUMMON_TYPE_SUMMON:
3120 EffectSummon(i);
3121 break;
3122 case SUMMON_TYPE_CRITTER:
3123 case SUMMON_TYPE_CRITTER2:
3124 case SUMMON_TYPE_CRITTER3:
3125 EffectSummonCritter(i);
3126 break;
3127 case SUMMON_TYPE_TOTEM_SLOT1:
3128 case SUMMON_TYPE_TOTEM_SLOT2:
3129 case SUMMON_TYPE_TOTEM_SLOT3:
3130 case SUMMON_TYPE_TOTEM_SLOT4:
3131 case SUMMON_TYPE_TOTEM:
3132 EffectSummonTotem(i);
3133 break;
3134 case SUMMON_TYPE_UNKNOWN1:
3135 case SUMMON_TYPE_UNKNOWN2:
3136 case SUMMON_TYPE_UNKNOWN3:
3137 case SUMMON_TYPE_UNKNOWN4:
3138 case SUMMON_TYPE_UNKNOWN5:
3139 break;
3140 default:
3141 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3142 break;
3146 void Spell::EffectSummon(uint32 i)
3148 if(m_caster->GetPetGUID())
3149 return;
3151 if(!unitTarget)
3152 return;
3153 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3154 if(!pet_entry)
3155 return;
3156 uint32 level = m_caster->getLevel();
3157 Pet* spawnCreature = new Pet(SUMMON_PET);
3159 if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
3161 // set timer for unsummon
3162 int32 duration = GetSpellDuration(m_spellInfo);
3163 if(duration > 0)
3164 spawnCreature->SetDuration(duration);
3166 return;
3169 Map *map = m_caster->GetMap();
3170 uint32 pet_number = objmgr.GeneratePetNumber();
3171 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3173 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3174 delete spawnCreature;
3175 return;
3178 // Summon in dest location
3179 float x,y,z;
3180 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3182 x = m_targets.m_destX;
3183 y = m_targets.m_destY;
3184 z = m_targets.m_destZ;
3186 else
3187 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3189 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3191 if(!spawnCreature->IsPositionValid())
3193 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3194 delete spawnCreature;
3195 return;
3198 // set timer for unsummon
3199 int32 duration = GetSpellDuration(m_spellInfo);
3200 if(duration > 0)
3201 spawnCreature->SetDuration(duration);
3203 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
3204 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3205 spawnCreature->setPowerType(POWER_MANA);
3206 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3207 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3208 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3209 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3210 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3211 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3212 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3213 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3214 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3216 spawnCreature->InitStatsForLevel(level);
3218 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3220 spawnCreature->AIM_Initialize();
3221 spawnCreature->InitPetCreateSpells();
3222 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3223 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3225 std::string name = m_caster->GetName();
3226 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3227 spawnCreature->SetName( name );
3229 map->Add((Creature*)spawnCreature);
3231 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3233 m_caster->SetPet(spawnCreature);
3234 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3235 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3236 ((Player*)m_caster)->PetSpellInitialize();
3240 void Spell::EffectLearnSpell(uint32 i)
3242 if(!unitTarget)
3243 return;
3245 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3247 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3248 EffectLearnPetSpell(i);
3250 return;
3253 Player *player = (Player*)unitTarget;
3255 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3256 player->learnSpell(spellToLearn);
3258 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3261 void Spell::EffectDispel(uint32 i)
3263 if(!unitTarget)
3264 return;
3266 // Fill possible dispell list
3267 std::vector <Aura *> dispel_list;
3269 // Create dispel mask by dispel type
3270 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3271 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3272 Unit::AuraMap const& auras = unitTarget->GetAuras();
3273 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3275 Aura *aur = (*itr).second;
3276 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3278 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3280 bool positive = true;
3281 if (!aur->IsPositive())
3282 positive = false;
3283 else
3284 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3286 // do not remove positive auras if friendly target
3287 // negative auras if non-friendly target
3288 if(positive == unitTarget->IsFriendlyTo(m_caster))
3289 continue;
3291 // Add aura to dispel list
3292 dispel_list.push_back(aur);
3295 // Ok if exist some buffs for dispel try dispel it
3296 if (!dispel_list.empty())
3298 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3299 std::list < uint32 > fail_list; // spell_id
3300 int32 list_size = dispel_list.size();
3301 // Dispell N = damage buffs (or while exist buffs for dispel)
3302 for (int32 count=0; count < damage && list_size > 0; ++count)
3304 // Random select buff for dispel
3305 Aura *aur = dispel_list[urand(0, list_size-1)];
3307 SpellEntry const* spellInfo = aur->GetSpellProto();
3308 // Base dispel chance
3309 // TODO: possible chance depend from spell level??
3310 int32 miss_chance = 0;
3311 // Apply dispel mod from aura caster
3312 if (Unit *caster = aur->GetCaster())
3314 if ( Player* modOwner = caster->GetSpellModOwner() )
3315 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3317 // Try dispel
3318 if (roll_chance_i(miss_chance))
3319 fail_list.push_back(aur->GetId());
3320 else
3321 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3322 // Remove buff from list for prevent doubles
3323 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3325 Aura *dispeled = *j;
3326 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3328 j = dispel_list.erase(j);
3329 --list_size;
3331 else
3332 ++j;
3335 // Send success log and really remove auras
3336 if (!success_list.empty())
3338 int32 count = success_list.size();
3339 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3340 data.append(unitTarget->GetPackGUID()); // Victim GUID
3341 data.append(m_caster->GetPackGUID()); // Caster GUID
3342 data << uint32(m_spellInfo->Id); // Dispell spell id
3343 data << uint8(0); // not used
3344 data << uint32(count); // count
3345 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3347 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3348 data << uint32(spellInfo->Id); // Spell Id
3349 data << uint8(0); // 0 - dispeled !=0 cleansed
3350 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3352 m_caster->SendMessageToSet(&data, true);
3354 // On succes dispel
3355 // Devour Magic
3356 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3358 uint32 heal_spell = 0;
3359 switch (m_spellInfo->Id)
3361 case 19505: heal_spell = 19658; break;
3362 case 19731: heal_spell = 19732; break;
3363 case 19734: heal_spell = 19733; break;
3364 case 19736: heal_spell = 19735; break;
3365 case 27276: heal_spell = 27278; break;
3366 case 27277: heal_spell = 27279; break;
3367 default:
3368 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3369 break;
3371 if (heal_spell)
3372 m_caster->CastSpell(m_caster, heal_spell, true);
3375 // Send fail log to client
3376 if (!fail_list.empty())
3378 // Failed to dispell
3379 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3380 data << uint64(m_caster->GetGUID()); // Caster GUID
3381 data << uint64(unitTarget->GetGUID()); // Victim GUID
3382 data << uint32(m_spellInfo->Id); // Dispell spell id
3383 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3384 data << uint32(*j); // Spell Id
3385 m_caster->SendMessageToSet(&data, true);
3390 void Spell::EffectDualWield(uint32 /*i*/)
3392 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
3393 ((Player*)unitTarget)->SetCanDualWield(true);
3396 void Spell::EffectPull(uint32 /*i*/)
3398 // TODO: create a proper pull towards distract spell center for distract
3399 sLog.outDebug("WORLD: Spell Effect DUMMY");
3402 void Spell::EffectDistract(uint32 /*i*/)
3404 // Check for possible target
3405 if (!unitTarget || unitTarget->isInCombat())
3406 return;
3408 // target must be OK to do this
3409 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3410 return;
3412 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3414 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3416 // For players just turn them
3417 WorldPacket data;
3418 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3419 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3420 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3422 else
3424 // Set creature Distracted, Stop it, And turn it
3425 unitTarget->SetOrientation(angle);
3426 unitTarget->StopMoving();
3427 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3431 void Spell::EffectPickPocket(uint32 /*i*/)
3433 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3434 return;
3436 // victim must be creature and attackable
3437 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3438 return;
3440 // victim have to be alive and humanoid or undead
3441 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3443 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3445 if (chance > irand(0, 19))
3447 // Stealing successful
3448 //sLog.outDebug("Sending loot from pickpocket");
3449 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3451 else
3453 // Reveal action + get attack
3454 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3455 if (((Creature*)unitTarget)->AI())
3456 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3461 void Spell::EffectAddFarsight(uint32 i)
3463 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3464 int32 duration = GetSpellDuration(m_spellInfo);
3465 DynamicObject* dynObj = new DynamicObject;
3466 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))
3468 delete dynObj;
3469 return;
3471 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3472 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3473 m_caster->AddDynObject(dynObj);
3474 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
3475 m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID());
3478 void Spell::EffectSummonWild(uint32 i)
3480 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3481 if(!creature_entry)
3482 return;
3484 uint32 level = m_caster->getLevel();
3486 // level of creature summoned using engineering item based at engineering skill level
3487 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3489 ItemPrototype const *proto = m_CastItem->GetProto();
3490 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3492 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3493 if(skill202)
3495 level = skill202/5;
3500 // select center of summon position
3501 float center_x = m_targets.m_destX;
3502 float center_y = m_targets.m_destY;
3503 float center_z = m_targets.m_destZ;
3505 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3507 int32 amount = damage > 0 ? damage : 1;
3509 for(int32 count = 0; count < amount; ++count)
3511 float px, py, pz;
3512 // If dest location if present
3513 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3515 // Summon 1 unit in dest location
3516 if (count == 0)
3518 px = m_targets.m_destX;
3519 py = m_targets.m_destY;
3520 pz = m_targets.m_destZ;
3522 // Summon in random point all other units if location present
3523 else
3524 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3526 // Summon if dest location not present near caster
3527 else
3528 m_caster->GetClosePoint(px,py,pz,3.0f);
3530 int32 duration = GetSpellDuration(m_spellInfo);
3532 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3534 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3538 void Spell::EffectSummonGuardian(uint32 i)
3540 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3541 if(!pet_entry)
3542 return;
3544 // Jewelery statue case (totem like)
3545 if(m_spellInfo->SpellIconID==2056)
3547 EffectSummonTotem(i);
3548 return;
3551 // set timer for unsummon
3552 int32 duration = GetSpellDuration(m_spellInfo);
3554 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3555 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3556 // so this code hack in fact
3557 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3558 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3559 return; // find old guardian, ignore summon
3561 // in another case summon new
3562 uint32 level = m_caster->getLevel();
3564 // level of pet summoned using engineering item based at engineering skill level
3565 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3567 ItemPrototype const *proto = m_CastItem->GetProto();
3568 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3570 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3571 if(skill202)
3573 level = skill202/5;
3578 // select center of summon position
3579 float center_x = m_targets.m_destX;
3580 float center_y = m_targets.m_destY;
3581 float center_z = m_targets.m_destZ;
3583 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3585 int32 amount = damage > 0 ? damage : 1;
3587 for(int32 count = 0; count < amount; ++count)
3589 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3591 Map *map = m_caster->GetMap();
3592 uint32 pet_number = objmgr.GeneratePetNumber();
3593 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3595 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3596 delete spawnCreature;
3597 return;
3600 float px, py, pz;
3601 // If dest location if present
3602 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3604 // Summon 1 unit in dest location
3605 if (count == 0)
3607 px = m_targets.m_destX;
3608 py = m_targets.m_destY;
3609 pz = m_targets.m_destZ;
3611 // Summon in random point all other units if location present
3612 else
3613 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3615 // Summon if dest location not present near caster
3616 else
3617 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3619 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3621 if(!spawnCreature->IsPositionValid())
3623 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3624 delete spawnCreature;
3625 return;
3628 if(duration > 0)
3629 spawnCreature->SetDuration(duration);
3631 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
3632 spawnCreature->setPowerType(POWER_MANA);
3633 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3634 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3635 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3636 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3637 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3638 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3639 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3641 spawnCreature->InitStatsForLevel(level);
3642 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3644 spawnCreature->AIM_Initialize();
3646 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3647 ((Player*)m_caster)->AddGuardian(spawnCreature);
3649 map->Add((Creature*)spawnCreature);
3653 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3655 if(!unitTarget)
3656 return;
3658 if(unitTarget->isInFlight())
3659 return;
3661 uint32 mapid = m_caster->GetMapId();
3662 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3664 float fx,fy,fz;
3665 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3667 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3668 ((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));
3669 else
3670 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3673 void Spell::EffectLearnSkill(uint32 i)
3675 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3676 return;
3678 if(damage < 0)
3679 return;
3681 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3682 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3683 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3686 void Spell::EffectAddHonor(uint32 /*i*/)
3688 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3689 return;
3691 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow());
3693 // TODO: find formula for honor reward based on player's level!
3695 // now fixed only for level 70 players:
3696 if (((Player*)unitTarget)->getLevel() == 70)
3697 ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage);
3700 void Spell::EffectTradeSkill(uint32 /*i*/)
3702 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3703 return;
3704 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3705 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3706 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3709 void Spell::EffectEnchantItemPerm(uint32 i)
3711 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3712 return;
3713 if (!itemTarget)
3714 return;
3716 Player* p_caster = (Player*)m_caster;
3718 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3720 if (m_spellInfo->EffectMiscValue[i])
3722 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3724 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3725 if(!pEnchant)
3726 return;
3728 // item can be in trade slot and have owner diff. from caster
3729 Player* item_owner = itemTarget->GetOwner();
3730 if(!item_owner)
3731 return;
3733 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3734 sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3735 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3736 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3737 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3739 // remove old enchanting before applying new if equipped
3740 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3742 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3744 // add new enchanting if equipped
3745 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3749 void Spell::EffectEnchantItemTmp(uint32 i)
3751 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3752 return;
3754 Player* p_caster = (Player*)m_caster;
3756 if(!itemTarget)
3757 return;
3759 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3761 // Shaman Rockbiter Weapon
3762 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3764 int32 enchnting_damage = m_currentBasePoints[1]+1;
3766 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3767 // with already applied percent bonus from Elemental Weapons talent
3768 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3769 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3770 switch(enchnting_damage)
3772 // Rank 1
3773 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3774 // Rank 2
3775 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3776 case 5: enchant_id = 3025; break; // 20%
3777 // Rank 3
3778 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3779 case 7: enchant_id = 3027; break; // 20%
3780 // Rank 4
3781 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3782 case 10: enchant_id = 503; break; // 14%
3783 case 11: enchant_id = 3031; break; // 20%
3784 // Rank 5
3785 case 15: enchant_id = 3035; break; // 0%
3786 case 16: enchant_id = 1663; break; // 7%
3787 case 17: enchant_id = 3033; break; // 14%
3788 case 18: enchant_id = 3034; break; // 20%
3789 // Rank 6
3790 case 28: enchant_id = 3038; break; // 0%
3791 case 29: enchant_id = 683; break; // 7%
3792 case 31: enchant_id = 3036; break; // 14%
3793 case 33: enchant_id = 3037; break; // 20%
3794 // Rank 7
3795 case 40: enchant_id = 3041; break; // 0%
3796 case 42: enchant_id = 1664; break; // 7%
3797 case 45: enchant_id = 3039; break; // 14%
3798 case 48: enchant_id = 3040; break; // 20%
3799 // Rank 8
3800 case 49: enchant_id = 3044; break; // 0%
3801 case 52: enchant_id = 2632; break; // 7%
3802 case 55: enchant_id = 3042; break; // 14%
3803 case 58: enchant_id = 3043; break; // 20%
3804 // Rank 9
3805 case 62: enchant_id = 2633; break; // 0%
3806 case 66: enchant_id = 3018; break; // 7%
3807 case 70: enchant_id = 3019; break; // 14%
3808 case 74: enchant_id = 3020; break; // 20%
3809 default:
3810 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3811 return;
3815 if (!enchant_id)
3817 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3818 return;
3821 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3822 if(!pEnchant)
3824 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3825 return;
3828 // select enchantment duration
3829 uint32 duration;
3831 // rogue family enchantments exception by duration
3832 if(m_spellInfo->Id==38615)
3833 duration = 1800; // 30 mins
3834 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3835 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3836 duration = 3600; // 1 hour
3837 // shaman family enchantments
3838 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3839 duration = 1800; // 30 mins
3840 // other cases with this SpellVisual already selected
3841 else if(m_spellInfo->SpellVisual==215)
3842 duration = 1800; // 30 mins
3843 // some fishing pole bonuses
3844 else if(m_spellInfo->SpellVisual==563)
3845 duration = 600; // 10 mins
3846 // shaman rockbiter enchantments
3847 else if(m_spellInfo->SpellVisual==0)
3848 duration = 1800; // 30 mins
3849 else if(m_spellInfo->Id==29702)
3850 duration = 300; // 5 mins
3851 else if(m_spellInfo->Id==37360)
3852 duration = 300; // 5 mins
3853 // default case
3854 else
3855 duration = 3600; // 1 hour
3857 // item can be in trade slot and have owner diff. from caster
3858 Player* item_owner = itemTarget->GetOwner();
3859 if(!item_owner)
3860 return;
3862 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3863 sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3864 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3865 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3866 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3868 // remove old enchanting before applying new if equipped
3869 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3871 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3873 // add new enchanting if equipped
3874 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3877 void Spell::EffectTameCreature(uint32 /*i*/)
3879 if(m_caster->GetPetGUID())
3880 return;
3882 if(!unitTarget)
3883 return;
3885 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3886 return;
3888 Creature* creatureTarget = (Creature*)unitTarget;
3890 if(creatureTarget->isPet())
3891 return;
3893 if(m_caster->getClass() == CLASS_HUNTER)
3895 // cast finish successfully
3896 //SendChannelUpdate(0);
3897 finish();
3899 Pet* pet = new Pet(HUNTER_PET);
3901 if(!pet->CreateBaseAtCreature(creatureTarget))
3903 delete pet;
3904 return;
3907 creatureTarget->setDeathState(JUST_DIED);
3908 creatureTarget->RemoveCorpse();
3909 creatureTarget->SetHealth(0); // just for nice GM-mode view
3911 pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
3912 pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3913 pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3914 pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3916 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
3917 pet->SetFreeTalentPoints(pet->GetMaxTalentPointsForLevel(level));
3919 if(!pet->InitStatsForLevel(level))
3921 sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
3922 delete pet;
3923 return;
3926 // prepare visual effect for levelup
3927 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
3929 pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
3930 // this enables pet details window (Shift+P)
3931 pet->AIM_Initialize();
3932 pet->InitPetCreateSpells();
3933 pet->SetHealth(pet->GetMaxHealth());
3935 MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
3937 // visual effect for levelup
3938 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
3940 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3942 m_caster->SetPet(pet);
3943 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3944 ((Player*)m_caster)->PetSpellInitialize();
3949 void Spell::EffectSummonPet(uint32 i)
3951 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3953 Pet *OldSummon = m_caster->GetPet();
3955 // if pet requested type already exist
3956 if( OldSummon )
3958 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3960 // pet in corpse state can't be summoned
3961 if( OldSummon->isDead() )
3962 return;
3964 MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false);
3965 OldSummon->SetMapId(m_caster->GetMapId());
3967 float px, py, pz;
3968 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3970 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3971 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon);
3973 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
3975 ((Player*)m_caster)->PetSpellInitialize();
3977 return;
3980 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3981 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
3982 else
3983 return;
3986 Pet* NewSummon = new Pet;
3988 // petentry==0 for hunter "call pet" (current pet summoned if any)
3989 if(NewSummon->LoadPetFromDB(m_caster,petentry))
3991 if(NewSummon->getPetType()==SUMMON_PET)
3993 // Remove Demonic Sacrifice auras (known pet)
3994 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
3995 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
3997 if((*itr)->GetModifier()->m_miscvalue==2228)
3999 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4000 itr = auraClassScripts.begin();
4002 else
4003 ++itr;
4007 return;
4010 // not error in case fail hunter call pet
4011 if(!petentry)
4013 delete NewSummon;
4014 return;
4017 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4019 if(!cInfo)
4021 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4022 delete NewSummon;
4023 return;
4026 Map *map = m_caster->GetMap();
4027 uint32 pet_number = objmgr.GeneratePetNumber();
4028 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4030 delete NewSummon;
4031 return;
4034 float px, py, pz;
4035 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4037 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4039 if(!NewSummon->IsPositionValid())
4041 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4042 delete NewSummon;
4043 return;
4046 uint32 petlevel = m_caster->getLevel();
4047 NewSummon->setPetType(SUMMON_PET);
4049 uint32 faction = m_caster->getFaction();
4050 if(m_caster->GetTypeId() == TYPEID_UNIT && ((Creature*)m_caster)->isTotem())
4052 Unit* owner = ((Totem*)m_caster)->GetOwner();
4053 if(owner)
4054 faction = owner->getFaction();
4055 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4058 NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
4059 NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
4060 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4061 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4062 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4063 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4064 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4065 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4066 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4067 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4069 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4070 // this enables pet details window (Shift+P)
4072 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4073 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4075 NewSummon->InitStatsForLevel(petlevel);
4076 NewSummon->InitPetCreateSpells();
4078 if(NewSummon->getPetType()==SUMMON_PET)
4080 // Remove Demonic Sacrifice auras (new pet)
4081 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4082 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4084 if((*itr)->GetModifier()->m_miscvalue==2228)
4086 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4087 itr = auraClassScripts.begin();
4089 else
4090 ++itr;
4093 // generate new name for summon pet
4094 std::string new_name=objmgr.GeneratePetName(petentry);
4095 if(!new_name.empty())
4096 NewSummon->SetName(new_name);
4098 else if(NewSummon->getPetType()==HUNTER_PET)
4099 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4101 NewSummon->AIM_Initialize();
4102 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4103 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4105 map->Add((Creature*)NewSummon);
4107 m_caster->SetPet(NewSummon);
4108 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4110 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4112 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4113 ((Player*)m_caster)->PetSpellInitialize();
4117 void Spell::EffectLearnPetSpell(uint32 i)
4119 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4120 return;
4122 Player *_player = (Player*)m_caster;
4124 Pet *pet = _player->GetPet();
4125 if(!pet)
4126 return;
4127 if(!pet->isAlive())
4128 return;
4130 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4131 if(!learn_spellproto)
4132 return;
4134 pet->learnSpell(learn_spellproto->Id);
4136 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4137 _player->PetSpellInitialize();
4140 void Spell::EffectTaunt(uint32 /*i*/)
4142 // this effect use before aura Taunt apply for prevent taunt already attacking target
4143 // for spell as marked "non effective at already attacking target"
4144 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4146 if(unitTarget->getVictim()==m_caster)
4148 SendCastResult(SPELL_FAILED_DONT_REPORT);
4149 return;
4153 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4154 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4155 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4158 void Spell::EffectWeaponDmg(uint32 i)
4160 if(!unitTarget)
4161 return;
4162 if(!unitTarget->isAlive())
4163 return;
4165 // multiple weapon dmg effect workaround
4166 // execute only the last weapon damage
4167 // and handle all effects at once
4168 for (int j = 0; j < 3; j++)
4170 switch(m_spellInfo->Effect[j])
4172 case SPELL_EFFECT_WEAPON_DAMAGE:
4173 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4174 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4175 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4176 if (j < i) // we must calculate only at last weapon effect
4177 return;
4178 break;
4182 // some spell specific modifiers
4183 bool customBonusDamagePercentMod = false;
4184 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4185 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4186 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4187 bool normalized = false;
4189 int32 spell_bonus = 0; // bonus specific for spell
4190 switch(m_spellInfo->SpellFamilyName)
4192 case SPELLFAMILY_WARRIOR:
4194 // Whirlwind, single only spell with 2 weapon white damage apply if have
4195 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4197 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4198 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4200 // Devastate bonus and sunder armor refresh
4201 else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
4203 customBonusDamagePercentMod = true;
4204 bonusDamagePercentMod = 0.0f; // only applied if auras found
4206 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4207 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4209 SpellEntry const *proto = (*itr)->GetSpellProto();
4210 if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
4212 int32 duration = GetSpellDuration(proto);
4213 (*itr)->SetAuraDuration(duration);
4214 (*itr)->SendAuraUpdate(false);
4215 bonusDamagePercentMod += 1.0f; // +100%
4219 break;
4221 case SPELLFAMILY_ROGUE:
4223 // Ambush
4224 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4226 customBonusDamagePercentMod = true;
4227 bonusDamagePercentMod = 2.5f; // 250%
4229 // Mutilate (for each hand)
4230 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4232 bool found = false;
4233 // fast check
4234 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4235 found = true;
4236 // full aura scan
4237 else
4239 Unit::AuraMap const& auras = unitTarget->GetAuras();
4240 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4242 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4244 found = true;
4245 break;
4250 if(found)
4251 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4253 break;
4255 case SPELLFAMILY_PALADIN:
4257 // Seal of Command - receive benefit from Spell Damage and Healing
4258 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4260 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4261 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4263 break;
4265 case SPELLFAMILY_SHAMAN:
4267 // Skyshatter Harness item set bonus
4268 // Stormstrike
4269 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4271 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4272 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4274 // Stormstrike AP Buff
4275 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4277 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4278 break;
4285 int32 fixed_bonus = 0;
4286 for (int j = 0; j < 3; j++)
4288 switch(m_spellInfo->Effect[j])
4290 case SPELL_EFFECT_WEAPON_DAMAGE:
4291 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4292 fixed_bonus += CalculateDamage(j,unitTarget);
4293 break;
4294 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4295 fixed_bonus += CalculateDamage(j,unitTarget);
4296 normalized = true;
4297 break;
4298 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4299 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4301 // applied only to prev.effects fixed damage
4302 if(customBonusDamagePercentMod)
4303 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4304 else
4305 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4306 break;
4307 default:
4308 break; // not weapon damage effect, just skip
4312 // non-weapon damage
4313 int32 bonus = spell_bonus + fixed_bonus;
4315 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4316 if(bonus)
4318 UnitMods unitMod;
4319 switch(m_attackType)
4321 default:
4322 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4323 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4324 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4327 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4328 bonus = int32(bonus*weapon_total_pct);
4331 // + weapon damage with applied weapon% dmg to base weapon damage in call
4332 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4334 // total damage
4335 bonus = int32(bonus*totalDamagePercentMod);
4337 // prevent negative damage
4338 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4340 const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
4342 uint32 hitInfo = 0;
4343 VictimState victimState = VICTIMSTATE_NORMAL;
4344 uint32 blocked_dmg = 0;
4345 uint32 absorbed_dmg = 0;
4346 uint32 resisted_dmg = 0;
4347 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
4349 m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
4351 if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
4352 m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
4354 bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
4355 m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
4357 if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
4359 eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
4361 else
4363 cleanDamage.damage += eff_damage;
4364 eff_damage = 0;
4367 // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
4368 m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
4370 // Hemorrhage
4371 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4373 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4374 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4377 // Mangle (Cat): CP
4378 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4380 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4381 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4384 // take ammo
4385 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4387 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4389 // wands don't have ammo
4390 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4391 return;
4393 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4395 if(pItem->GetMaxStackCount()==1)
4397 // decrease durability for non-stackable throw weapon
4398 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4400 else
4402 // decrease items amount for stackable throw weapon
4403 uint32 count = 1;
4404 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4407 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4408 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4412 void Spell::EffectThreat(uint32 /*i*/)
4414 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4415 return;
4417 if(!unitTarget->CanHaveThreatList())
4418 return;
4420 unitTarget->AddThreat(m_caster, float(damage));
4423 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4425 if(!unitTarget)
4426 return;
4427 if(!unitTarget->isAlive())
4428 return;
4430 uint32 heal = m_caster->GetMaxHealth();
4432 int32 gain = unitTarget->ModifyHealth(heal);
4433 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
4435 m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
4438 void Spell::EffectInterruptCast(uint32 /*i*/)
4440 if(!unitTarget)
4441 return;
4442 if(!unitTarget->isAlive())
4443 return;
4445 // TODO: not all spells that used this effect apply cooldown at school spells
4446 // also exist case: apply cooldown to interrupted cast only and to all spells
4447 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4449 if (unitTarget->m_currentSpells[i])
4451 // check if we can interrupt spell
4452 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4454 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4455 unitTarget->InterruptSpell(i,false);
4461 void Spell::EffectSummonObjectWild(uint32 i)
4463 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4465 GameObject* pGameObj = new GameObject;
4467 WorldObject* target = focusObject;
4468 if( !target )
4469 target = m_caster;
4471 float x,y,z;
4472 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4474 x = m_targets.m_destX;
4475 y = m_targets.m_destY;
4476 z = m_targets.m_destZ;
4478 else
4479 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4481 Map *map = target->GetMap();
4483 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4484 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4486 delete pGameObj;
4487 return;
4490 int32 duration = GetSpellDuration(m_spellInfo);
4491 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4492 pGameObj->SetSpellId(m_spellInfo->Id);
4494 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4495 m_caster->AddGameObject(pGameObj);
4496 map->Add(pGameObj);
4498 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4500 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4502 Player *pl = (Player*)m_caster;
4503 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4504 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4506 uint32 team = ALLIANCE;
4508 if(pl->GetTeam() == team)
4509 team = HORDE;
4511 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4516 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4518 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4520 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4521 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4523 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4528 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4530 GameObject* linkedGO = new GameObject;
4531 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4532 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4534 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4535 linkedGO->SetSpellId(m_spellInfo->Id);
4537 m_caster->AddGameObject(linkedGO);
4538 map->Add(linkedGO);
4540 else
4542 delete linkedGO;
4543 linkedGO = NULL;
4544 return;
4549 void Spell::EffectScriptEffect(uint32 effIndex)
4551 // TODO: we must implement hunter pet summon at login there (spell 6962)
4553 // by spell id
4554 switch(m_spellInfo->Id)
4556 // Bending Shinbone
4557 case 8856:
4559 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4560 return;
4562 uint32 spell_id = 0;
4563 switch(urand(1,5))
4565 case 1: spell_id = 8854; break;
4566 default: spell_id = 8855; break;
4569 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4570 return;
4573 // Healthstone creating spells
4574 case 6201:
4575 case 6202:
4576 case 5699:
4577 case 11729:
4578 case 11730:
4579 case 27230:
4581 uint32 itemtype;
4582 uint32 rank = 0;
4583 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4584 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4586 if((*i)->GetId() == 18692)
4588 rank = 1;
4589 break;
4591 else if((*i)->GetId() == 18693)
4593 rank = 2;
4594 break;
4598 static uint32 const itypes[6][3] = {
4599 { 5512,19004,19005}, // Minor Healthstone
4600 { 5511,19006,19007}, // Lesser Healthstone
4601 { 5509,19008,19009}, // Healthstone
4602 { 5510,19010,19011}, // Greater Healthstone
4603 { 9421,19012,19013}, // Major Healthstone
4604 {22103,22104,22105} // Master Healthstone
4607 switch(m_spellInfo->Id)
4609 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4610 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4611 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4612 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4613 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4614 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4615 default:
4616 return;
4618 DoCreateItem( effIndex, itemtype );
4619 return;
4621 // Brittle Armor - need remove one 24575 Brittle Armor aura
4622 case 24590:
4623 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4624 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4625 return;
4626 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4627 case 26465:
4628 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4629 return;
4630 // Orb teleport spells
4631 case 25140:
4632 case 25143:
4633 case 25650:
4634 case 25652:
4635 case 29128:
4636 case 29129:
4637 case 35376:
4638 case 35727:
4640 if(!unitTarget)
4641 return;
4643 uint32 spellid;
4644 switch(m_spellInfo->Id)
4646 case 25140: spellid = 32571; break;
4647 case 25143: spellid = 32572; break;
4648 case 25650: spellid = 30140; break;
4649 case 25652: spellid = 30141; break;
4650 case 29128: spellid = 32568; break;
4651 case 29129: spellid = 32569; break;
4652 case 35376: spellid = 25649; break;
4653 case 35727: spellid = 35730; break;
4654 default:
4655 return;
4658 unitTarget->CastSpell(unitTarget,spellid,false);
4659 return;
4662 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4663 case 22539:
4664 case 22972:
4665 case 22975:
4666 case 22976:
4667 case 22977:
4668 case 22978:
4669 case 22979:
4670 case 22980:
4671 case 22981:
4672 case 22982:
4673 case 22983:
4674 case 22984:
4675 case 22985:
4677 if(!unitTarget || !unitTarget->isAlive())
4678 return;
4680 // Onyxia Scale Cloak
4681 if(unitTarget->GetDummyAura(22683))
4682 return;
4684 // Shadow Flame
4685 m_caster->CastSpell(unitTarget, 22682, true);
4686 return;
4688 break;
4690 // Summon Black Qiraji Battle Tank
4691 case 26656:
4693 if(!unitTarget)
4694 return;
4696 // Prevent stacking of mounts
4697 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4699 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4700 if (unitTarget->GetAreaId() == 3428)
4701 unitTarget->CastSpell(unitTarget, 25863, false);
4702 else
4703 unitTarget->CastSpell(unitTarget, 26655, false);
4704 break;
4706 // Piccolo of the Flaming Fire
4707 case 17512:
4709 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4710 return;
4711 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4712 break;
4715 // Dreaming Glory
4716 case 28698:
4718 if(!unitTarget)
4719 return;
4720 unitTarget->CastSpell(unitTarget, 28694, true);
4721 break;
4724 // Netherbloom
4725 case 28702:
4727 if(!unitTarget)
4728 return;
4729 // 25% chance of casting a random buff
4730 if(roll_chance_i(75))
4731 return;
4733 // triggered spells are 28703 to 28707
4734 // Note: some sources say, that there was the possibility of
4735 // receiving a debuff. However, this seems to be removed by a patch.
4736 const uint32 spellid = 28703;
4738 // don't overwrite an existing aura
4739 for(uint8 i=0; i<5; i++)
4740 if(unitTarget->HasAura(spellid+i, 0))
4741 return;
4742 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4743 break;
4746 // Nightmare Vine
4747 case 28720:
4749 if(!unitTarget)
4750 return;
4751 // 25% chance of casting Nightmare Pollen
4752 if(roll_chance_i(75))
4753 return;
4754 unitTarget->CastSpell(unitTarget, 28721, true);
4755 break;
4758 // Mirren's Drinking Hat
4759 case 29830:
4761 uint32 item = 0;
4762 switch ( urand(1,6) )
4764 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4765 case 4: case 5: item = 23585; break;// Stouthammer Lite
4766 case 6: item = 23586; break;// Aerie Peak Pale Ale
4768 if (item)
4769 DoCreateItem(effIndex,item);
4770 break;
4772 // Improved Sprint
4773 case 30918:
4775 // Removes snares and roots.
4776 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4777 Unit::AuraMap& Auras = unitTarget->GetAuras();
4778 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4780 next = iter;
4781 ++next;
4782 Aura *aur = iter->second;
4783 if (!aur->IsPositive()) //only remove negative spells
4785 // check for mechanic mask
4786 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4788 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4789 if(Auras.empty())
4790 break;
4791 else
4792 next = Auras.begin();
4796 break;
4798 case 41126: // Flame Crash
4800 if(!unitTarget)
4801 return;
4803 unitTarget->CastSpell(unitTarget, 41131, true);
4804 break;
4806 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4808 if(!unitTarget)
4809 return;
4811 unitTarget->CastSpell(unitTarget, 44870, true);
4812 break;
4815 // Goblin Weather Machine
4816 case 46203:
4818 if(!unitTarget)
4819 return;
4821 uint32 spellId;
4822 switch(rand()%4)
4824 case 0:
4825 spellId=46740;
4826 break;
4827 case 1:
4828 spellId=46739;
4829 break;
4830 case 2:
4831 spellId=46738;
4832 break;
4833 case 3:
4834 spellId=46736;
4835 break;
4837 unitTarget->CastSpell(unitTarget, spellId, true);
4838 break;
4840 //5,000 Gold
4841 case 46642:
4843 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4844 return;
4846 ((Player*)unitTarget)->ModifyMoney(50000000);
4848 break;
4852 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4854 switch(m_spellInfo->SpellFamilyFlags)
4856 // Judgement
4857 case 0x800000:
4859 if(!unitTarget || !unitTarget->isAlive())
4860 return;
4861 uint32 spellId2 = 0;
4863 // all seals have aura dummy
4864 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4865 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4867 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4869 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4870 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4871 continue;
4873 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4874 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4876 if(spellId2 <= 1)
4877 continue;
4879 // found, remove seal
4880 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4882 // Sanctified Judgement
4883 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4884 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4886 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4888 int32 chance = (*i)->GetModifier()->m_amount;
4889 if ( roll_chance_i(chance) )
4891 int32 mana = spellInfo->manaCost;
4892 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4893 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4894 mana = int32(mana* 0.8f);
4895 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4897 break;
4901 break;
4904 m_caster->CastSpell(unitTarget,spellId2,true);
4905 return;
4910 // normal DB scripted effect
4911 if(!unitTarget)
4912 return;
4914 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
4915 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
4918 void Spell::EffectSanctuary(uint32 /*i*/)
4920 if(!unitTarget)
4921 return;
4922 //unitTarget->CombatStop();
4924 unitTarget->CombatStop();
4925 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
4926 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4927 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
4929 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4933 void Spell::EffectAddComboPoints(uint32 /*i*/)
4935 if(!unitTarget)
4936 return;
4938 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4939 return;
4941 if(damage <= 0)
4942 return;
4944 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
4947 void Spell::EffectDuel(uint32 i)
4949 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4950 return;
4952 Player *caster = (Player*)m_caster;
4953 Player *target = (Player*)unitTarget;
4955 // caster or target already have requested duel
4956 if( caster->duel || target->duel || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
4957 return;
4959 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4960 // Don't have to check the target's map since you cannot challenge someone across maps
4961 if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530)
4963 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4964 return;
4967 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
4968 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
4970 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4971 return;
4974 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
4975 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
4977 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4978 return;
4981 //CREATE DUEL FLAG OBJECT
4982 GameObject* pGameObj = new GameObject;
4984 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4986 Map *map = m_caster->GetMap();
4987 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4988 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
4989 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
4990 m_caster->GetPositionZ(),
4991 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
4993 delete pGameObj;
4994 return;
4997 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
4998 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
4999 int32 duration = GetSpellDuration(m_spellInfo);
5000 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5001 pGameObj->SetSpellId(m_spellInfo->Id);
5003 m_caster->AddGameObject(pGameObj);
5004 map->Add(pGameObj);
5005 //END
5007 // Send request
5008 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5009 data << pGameObj->GetGUID();
5010 data << caster->GetGUID();
5011 caster->GetSession()->SendPacket(&data);
5012 target->GetSession()->SendPacket(&data);
5014 // create duel-info
5015 DuelInfo *duel = new DuelInfo;
5016 duel->initiator = caster;
5017 duel->opponent = target;
5018 duel->startTime = 0;
5019 duel->startTimer = 0;
5020 caster->duel = duel;
5022 DuelInfo *duel2 = new DuelInfo;
5023 duel2->initiator = caster;
5024 duel2->opponent = caster;
5025 duel2->startTime = 0;
5026 duel2->startTimer = 0;
5027 target->duel = duel2;
5029 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5030 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5033 void Spell::EffectStuck(uint32 /*i*/)
5035 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5036 return;
5038 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5039 return;
5041 Player* pTarget = (Player*)unitTarget;
5043 sLog.outDebug("Spell Effect: Stuck");
5044 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());
5046 if(pTarget->isInFlight())
5047 return;
5049 // homebind location is loaded always
5050 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5052 // Stuck spell trigger Hearthstone cooldown
5053 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5054 if(!spellInfo)
5055 return;
5056 Spell spell(pTarget,spellInfo,true,0);
5057 spell.SendSpellCooldown();
5060 void Spell::EffectSummonPlayer(uint32 /*i*/)
5062 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5063 return;
5065 // Evil Twin (ignore player summon, but hide this for summoner)
5066 if(unitTarget->GetDummyAura(23445))
5067 return;
5069 float x,y,z;
5070 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5072 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5074 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5075 data << uint64(m_caster->GetGUID()); // summoner guid
5076 data << uint32(m_caster->GetZoneId()); // summoner zone
5077 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5078 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5081 static ScriptInfo generateActivateCommand()
5083 ScriptInfo si;
5084 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5085 return si;
5088 void Spell::EffectActivateObject(uint32 effect_idx)
5090 if(!gameObjTarget)
5091 return;
5093 static ScriptInfo activateCommand = generateActivateCommand();
5095 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5097 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5100 void Spell::EffectApplyGlyph(uint32 i)
5102 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5103 return;
5105 Player *player = (Player*)m_caster;
5107 // remove old glyph
5108 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5110 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5112 player->RemoveAurasDueToSpell(old_gp->SpellId);
5113 player->SetGlyph(m_glyphIndex, 0);
5117 // apply new one
5118 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5120 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5122 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5124 if(gp->TypeFlags != gs->TypeFlags)
5126 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5127 return; // glyph slot missmatch
5131 player->CastSpell(m_caster, gp->SpellId, true);
5132 player->SetGlyph(m_glyphIndex, glyph);
5133 if(m_CastItem)
5134 player->DestroyItemCount(m_CastItem->GetEntry(), 1, true);
5139 void Spell::EffectSummonTotem(uint32 i)
5141 uint8 slot = 0;
5142 switch(m_spellInfo->EffectMiscValueB[i])
5144 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5145 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5146 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5147 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5148 // Battle standard case
5149 case SUMMON_TYPE_TOTEM: slot = 254; break;
5150 // jewelery statue case, like totem without slot
5151 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5152 default: return;
5155 if(slot < MAX_TOTEM)
5157 uint64 guid = m_caster->m_TotemSlot[slot];
5158 if(guid != 0)
5160 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5161 if(OldTotem && OldTotem->isTotem())
5162 ((Totem*)OldTotem)->UnSummon();
5166 uint32 team = 0;
5167 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5168 team = ((Player*)m_caster)->GetTeam();
5170 Totem* pTotem = new Totem;
5172 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5174 delete pTotem;
5175 return;
5178 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5180 float x,y,z;
5181 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5183 // totem must be at same Z in case swimming caster and etc.
5184 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5185 z = m_caster->GetPositionZ();
5187 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5189 if(slot < MAX_TOTEM)
5190 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5192 pTotem->SetOwner(m_caster->GetGUID());
5193 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5195 int32 duration=GetSpellDuration(m_spellInfo);
5196 if(Player* modOwner = m_caster->GetSpellModOwner())
5197 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5198 pTotem->SetDuration(duration);
5200 if (damage) // if not spell info, DB values used
5202 pTotem->SetMaxHealth(damage);
5203 pTotem->SetHealth(damage);
5206 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5207 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5209 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5210 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5212 pTotem->Summon(m_caster);
5214 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5216 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5217 data << uint8(slot);
5218 data << uint64(pTotem->GetGUID());
5219 data << uint32(duration);
5220 data << uint32(m_spellInfo->Id);
5221 ((Player*)m_caster)->SendDirectMessage(&data);
5225 void Spell::EffectEnchantHeldItem(uint32 i)
5227 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5228 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5229 return;
5231 Player* item_owner = (Player*)unitTarget;
5232 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5234 if(!item )
5235 return;
5237 // must be equipped
5238 if(!item ->IsEquipped())
5239 return;
5241 if (m_spellInfo->EffectMiscValue[i])
5243 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5244 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5245 if(!duration)
5246 duration = m_currentBasePoints[i]+1; //Base points after ..
5247 if(!duration)
5248 duration = 10; //10 seconds for enchants which don't have listed duration
5250 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5251 if(!pEnchant)
5252 return;
5254 // Always go to temp enchantment slot
5255 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5257 // Enchantment will not be applied if a different one already exists
5258 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5259 return;
5261 // Apply the temporary enchantment
5262 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5263 item_owner->ApplyEnchantment(item,slot,true);
5267 void Spell::EffectDisEnchant(uint32 /*i*/)
5269 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5270 return;
5272 Player* p_caster = (Player*)m_caster;
5273 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5274 return;
5276 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5278 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5280 // item will be removed at disenchanting end
5283 void Spell::EffectInebriate(uint32 /*i*/)
5285 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5286 return;
5288 Player *player = (Player*)unitTarget;
5289 uint16 currentDrunk = player->GetDrunkValue();
5290 uint16 drunkMod = damage * 256;
5291 if (currentDrunk + drunkMod > 0xFFFF)
5292 currentDrunk = 0xFFFF;
5293 else
5294 currentDrunk += drunkMod;
5295 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5298 void Spell::EffectFeedPet(uint32 i)
5300 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5301 return;
5303 Player *_player = (Player*)m_caster;
5305 if(!itemTarget)
5306 return;
5308 Pet *pet = _player->GetPet();
5309 if(!pet)
5310 return;
5312 if(!pet->isAlive())
5313 return;
5315 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5316 if(benefit <= 0)
5317 return;
5319 uint32 count = 1;
5320 _player->DestroyItemCount(itemTarget,count,true);
5321 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5323 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5326 void Spell::EffectDismissPet(uint32 /*i*/)
5328 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5329 return;
5331 Pet* pet = m_caster->GetPet();
5333 // not let dismiss dead pet
5334 if(!pet||!pet->isAlive())
5335 return;
5337 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5340 void Spell::EffectSummonObject(uint32 i)
5342 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5344 uint8 slot = 0;
5345 switch(m_spellInfo->Effect[i])
5347 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5348 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5349 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5350 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5351 default: return;
5354 uint64 guid = m_caster->m_ObjectSlot[slot];
5355 if(guid != 0)
5357 GameObject* obj = NULL;
5358 if( m_caster )
5359 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5361 if(obj) obj->Delete();
5362 m_caster->m_ObjectSlot[slot] = 0;
5365 GameObject* pGameObj = new GameObject;
5367 float rot2 = sin(m_caster->GetOrientation()/2);
5368 float rot3 = cos(m_caster->GetOrientation()/2);
5370 float x,y,z;
5371 // If dest location if present
5372 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5374 x = m_targets.m_destX;
5375 y = m_targets.m_destY;
5376 z = m_targets.m_destZ;
5378 // Summon in random point all other units if location present
5379 else
5380 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5382 Map *map = m_caster->GetMap();
5383 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5385 delete pGameObj;
5386 return;
5389 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5390 int32 duration = GetSpellDuration(m_spellInfo);
5391 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5392 pGameObj->SetSpellId(m_spellInfo->Id);
5393 m_caster->AddGameObject(pGameObj);
5395 map->Add(pGameObj);
5396 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5397 data << pGameObj->GetGUID();
5398 m_caster->SendMessageToSet(&data,true);
5400 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5403 void Spell::EffectResurrect(uint32 i)
5405 if(!unitTarget)
5406 return;
5407 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5408 return;
5410 if(unitTarget->isAlive())
5411 return;
5412 if(!unitTarget->IsInWorld())
5413 return;
5415 switch (m_spellInfo->Id)
5417 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5418 case 8342:
5419 if (roll_chance_i(67))
5421 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5422 return;
5424 break;
5425 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5426 case 22999:
5427 if (roll_chance_i(50))
5429 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5430 return;
5432 break;
5433 default:
5434 break;
5437 Player* pTarget = ((Player*)unitTarget);
5439 if(pTarget->isRessurectRequested()) // already have one active request
5440 return;
5442 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5443 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5445 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5446 SendResurrectRequest(pTarget);
5449 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5451 if(!unitTarget || !unitTarget->isAlive())
5452 return;
5454 if( unitTarget->m_extraAttacks )
5455 return;
5457 unitTarget->m_extraAttacks = damage;
5460 void Spell::EffectParry(uint32 /*i*/)
5462 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5464 ((Player*)unitTarget)->SetCanParry(true);
5468 void Spell::EffectBlock(uint32 /*i*/)
5470 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5471 return;
5473 ((Player*)unitTarget)->SetCanBlock(true);
5476 void Spell::EffectMomentMove(uint32 i)
5478 if(unitTarget->isInFlight())
5479 return;
5481 if( m_spellInfo->rangeIndex== 1) //self range
5483 uint32 mapid = m_caster->GetMapId();
5484 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5486 // before caster
5487 float fx,fy,fz;
5488 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5489 float ox,oy,oz;
5490 unitTarget->GetPosition(ox,oy,oz);
5492 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5493 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5495 fx = fx2;
5496 fy = fy2;
5497 fz = fz2;
5498 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5501 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5502 ((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));
5503 else
5504 MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5508 void Spell::EffectReputation(uint32 i)
5510 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5511 return;
5513 Player *_player = (Player*)unitTarget;
5515 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5517 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5519 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5521 if(!factionEntry)
5522 return;
5524 _player->ModifyFactionReputation(factionEntry,rep_change);
5527 void Spell::EffectQuestComplete(uint32 i)
5529 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5530 return;
5532 Player *_player = (Player*)m_caster;
5534 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5535 _player->AreaExploredOrEventHappens(quest_id);
5538 void Spell::EffectSelfResurrect(uint32 i)
5540 if(!unitTarget || unitTarget->isAlive())
5541 return;
5542 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5543 return;
5544 if(!unitTarget->IsInWorld())
5545 return;
5547 uint32 health = 0;
5548 uint32 mana = 0;
5550 // flat case
5551 if(damage < 0)
5553 health = uint32(-damage);
5554 mana = m_spellInfo->EffectMiscValue[i];
5556 // percent case
5557 else
5559 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5560 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5561 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5564 Player *plr = ((Player*)unitTarget);
5565 plr->ResurrectPlayer(0.0f);
5567 plr->SetHealth( health );
5568 plr->SetPower(POWER_MANA, mana );
5569 plr->SetPower(POWER_RAGE, 0 );
5570 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5572 plr->SpawnCorpseBones();
5574 plr->SaveToDB();
5577 void Spell::EffectSkinning(uint32 /*i*/)
5579 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5580 return;
5581 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5582 return;
5584 Creature* creature = (Creature*) unitTarget;
5585 int32 targetLevel = creature->getLevel();
5587 uint32 skill;
5588 if(creature->GetCreatureInfo()->flag1 & 256)
5589 skill = SKILL_HERBALISM; // special case
5590 else if(creature->GetCreatureInfo()->flag1 & 512)
5591 skill = SKILL_MINING; // special case
5592 else
5593 skill = SKILL_SKINNING; // normal case
5595 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5596 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5598 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5600 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5602 // Double chances for elites
5603 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5606 void Spell::EffectCharge(uint32 /*i*/)
5608 if(!unitTarget || !m_caster)
5609 return;
5611 float x, y, z;
5612 unitTarget->GetContactPoint(m_caster, x, y, z);
5613 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5614 ((Creature *)unitTarget)->StopMoving();
5616 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5617 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5619 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5620 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5622 // not all charge effects used in negative spells
5623 if ( !IsPositiveSpell(m_spellInfo->Id))
5624 m_caster->Attack(unitTarget,true);
5627 void Spell::EffectSummonCritter(uint32 i)
5629 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5630 return;
5631 Player* player = (Player*)m_caster;
5633 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5634 if(!pet_entry)
5635 return;
5637 Pet* old_critter = player->GetMiniPet();
5639 // for same pet just despawn
5640 if(old_critter && old_critter->GetEntry() == pet_entry)
5642 player->RemoveMiniPet();
5643 return;
5646 // despawn old pet before summon new
5647 if(old_critter)
5648 player->RemoveMiniPet();
5650 // summon new pet
5651 Pet* critter = new Pet(MINI_PET);
5653 Map *map = m_caster->GetMap();
5654 uint32 pet_number = objmgr.GeneratePetNumber();
5655 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5656 map, pet_entry, pet_number))
5658 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5659 delete critter;
5660 return;
5663 float x,y,z;
5664 // If dest location if present
5665 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5667 x = m_targets.m_destX;
5668 y = m_targets.m_destY;
5669 z = m_targets.m_destZ;
5671 // Summon if dest location not present near caster
5672 else
5673 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5675 critter->Relocate(x,y,z,m_caster->GetOrientation());
5677 if(!critter->IsPositionValid())
5679 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5680 delete critter;
5681 return;
5684 critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
5685 critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID());
5686 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5687 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5689 critter->AIM_Initialize();
5690 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5691 critter->SetMaxHealth(1);
5692 critter->SetHealth(1);
5693 critter->SetLevel(1);
5695 // set timer for unsummon
5696 int32 duration = GetSpellDuration(m_spellInfo);
5697 if(duration > 0)
5698 critter->SetDuration(duration);
5700 std::string name = player->GetName();
5701 name.append(petTypeSuffix[critter->getPetType()]);
5702 critter->SetName( name );
5703 player->SetMiniPet(critter);
5705 map->Add((Creature*)critter);
5708 void Spell::EffectKnockBack(uint32 i)
5710 if(!unitTarget || !m_caster)
5711 return;
5713 // Effect only works on players
5714 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5715 return;
5717 float vsin = sin(m_caster->GetAngle(unitTarget));
5718 float vcos = cos(m_caster->GetAngle(unitTarget));
5720 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5721 data.append(unitTarget->GetPackGUID());
5722 data << uint32(0); // Sequence
5723 data << float(vcos); // x direction
5724 data << float(vsin); // y direction
5725 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5726 data << float(damage/-10); // Z Movement speed (vertical)
5728 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5731 void Spell::EffectSendTaxi(uint32 i)
5733 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5734 return;
5736 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5737 if(!entry)
5738 return;
5740 std::vector<uint32> nodes;
5742 nodes.resize(2);
5743 nodes[0] = entry->from;
5744 nodes[1] = entry->to;
5746 uint32 mountid = 0;
5747 switch(m_spellInfo->Id)
5749 case 31606: //Stormcrow Amulet
5750 mountid = 17447;
5751 break;
5752 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5753 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5754 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5755 mountid = 22840;
5756 break;
5757 case 34905: //Stealth Flight
5758 mountid = 6851;
5759 break;
5762 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5766 void Spell::EffectPlayerPull(uint32 i)
5768 if(!unitTarget || !m_caster)
5769 return;
5771 // Effect only works on players
5772 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5773 return;
5775 float vsin = sin(unitTarget->GetAngle(m_caster));
5776 float vcos = cos(unitTarget->GetAngle(m_caster));
5778 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5779 data.append(unitTarget->GetPackGUID());
5780 data << uint32(0); // Sequence
5781 data << float(vcos); // x direction
5782 data << float(vsin); // y direction
5783 // Horizontal speed
5784 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5785 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5787 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5790 void Spell::EffectDispelMechanic(uint32 i)
5792 if(!unitTarget)
5793 return;
5795 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5797 Unit::AuraMap& Auras = unitTarget->GetAuras();
5798 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5800 next = iter;
5801 ++next;
5802 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5803 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5805 unitTarget->RemoveAurasDueToSpell(spell->Id);
5806 if(Auras.empty())
5807 break;
5808 else
5809 next = Auras.begin();
5812 return;
5815 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5817 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5818 return;
5819 Player *_player = (Player*)m_caster;
5820 Pet *pet = _player->GetPet();
5821 if(!pet)
5822 return;
5823 if(pet->isAlive())
5824 return;
5825 if(damage < 0)
5826 return;
5827 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5828 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5829 pet->setDeathState( ALIVE );
5830 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5831 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5833 pet->AIM_Initialize();
5835 _player->PetSpellInitialize();
5836 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5839 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5841 float mana = 0;
5842 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5844 if(!m_caster->m_TotemSlot[slot])
5845 continue;
5847 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5848 if(totem && totem->isTotem())
5850 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5851 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5852 if(spellInfo)
5853 mana += spellInfo->manaCost * damage / 100;
5854 ((Totem*)totem)->UnSummon();
5858 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5859 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5862 void Spell::EffectDurabilityDamage(uint32 i)
5864 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5865 return;
5867 int32 slot = m_spellInfo->EffectMiscValue[i];
5869 // FIXME: some spells effects have value -1/-2
5870 // Possibly its mean -1 all player equipped items and -2 all items
5871 if(slot < 0)
5873 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5874 return;
5877 // invalid slot value
5878 if(slot >= INVENTORY_SLOT_BAG_END)
5879 return;
5881 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5882 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5885 void Spell::EffectDurabilityDamagePCT(uint32 i)
5887 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5888 return;
5890 int32 slot = m_spellInfo->EffectMiscValue[i];
5892 // FIXME: some spells effects have value -1/-2
5893 // Possibly its mean -1 all player equipped items and -2 all items
5894 if(slot < 0)
5896 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5897 return;
5900 // invalid slot value
5901 if(slot >= INVENTORY_SLOT_BAG_END)
5902 return;
5904 if(damage <= 0)
5905 return;
5907 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5908 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
5911 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
5913 if(!unitTarget)
5914 return;
5916 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5919 void Spell::EffectTransmitted(uint32 effIndex)
5921 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
5923 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
5925 if (!goinfo)
5927 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
5928 return;
5931 float fx,fy,fz;
5933 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5935 fx = m_targets.m_destX;
5936 fy = m_targets.m_destY;
5937 fz = m_targets.m_destZ;
5939 //FIXME: this can be better check for most objects but still hack
5940 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
5942 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
5943 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5945 else
5947 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5948 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5949 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
5951 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5954 Map *cMap = m_caster->GetMap();
5956 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
5958 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
5959 { // but this is not proper, we really need to ignore not materialized objects
5960 SendCastResult(SPELL_FAILED_NOT_HERE);
5961 SendChannelUpdate(0);
5962 return;
5965 // replace by water level in this case
5966 fz = cMap->GetWaterLevel(fx,fy);
5968 // if gameobject is summoning object, it should be spawned right on caster's position
5969 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5971 m_caster->GetPosition(fx,fy,fz);
5974 GameObject* pGameObj = new GameObject;
5976 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5977 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5979 delete pGameObj;
5980 return;
5983 int32 duration = GetSpellDuration(m_spellInfo);
5985 switch(goinfo->type)
5987 case GAMEOBJECT_TYPE_FISHINGNODE:
5989 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
5990 // Orientation3
5991 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
5992 // Orientation4
5993 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
5994 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5996 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5997 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5998 int32 lastSec;
5999 switch(urand(0, 3))
6001 case 0: lastSec = 3; break;
6002 case 1: lastSec = 7; break;
6003 case 2: lastSec = 13; break;
6004 case 3: lastSec = 17; break;
6007 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6008 break;
6010 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6012 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6014 pGameObj->AddUniqueUse((Player*)m_caster);
6015 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6017 break;
6019 case GAMEOBJECT_TYPE_FISHINGHOLE:
6020 case GAMEOBJECT_TYPE_CHEST:
6021 default:
6023 break;
6027 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6029 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6031 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6032 pGameObj->SetSpellId(m_spellInfo->Id);
6034 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6035 //m_caster->AddGameObject(pGameObj);
6036 //m_ObjToDel.push_back(pGameObj);
6038 cMap->Add(pGameObj);
6040 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6041 data << uint64(pGameObj->GetGUID());
6042 m_caster->SendMessageToSet(&data,true);
6044 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6046 GameObject* linkedGO = new GameObject;
6047 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6048 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6050 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6051 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6052 linkedGO->SetSpellId(m_spellInfo->Id);
6053 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6055 MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->Add(linkedGO);
6057 else
6059 delete linkedGO;
6060 linkedGO = NULL;
6061 return;
6066 void Spell::EffectProspecting(uint32 /*i*/)
6068 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6069 return;
6071 Player* p_caster = (Player*)m_caster;
6072 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6073 return;
6075 if(itemTarget->GetCount() < 5)
6076 return;
6078 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6080 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6081 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6082 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6085 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6088 void Spell::EffectSkill(uint32 /*i*/)
6090 sLog.outDebug("WORLD: SkillEFFECT");
6093 void Spell::EffectSummonDemon(uint32 i)
6095 float px = m_targets.m_destX;
6096 float py = m_targets.m_destY;
6097 float pz = m_targets.m_destZ;
6099 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6100 if (!Charmed)
6101 return;
6103 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6104 Charmed->SetLevel(m_caster->getLevel());
6106 // TODO: Add damage/mana/hp according to level
6108 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6110 // Enslave demon effect, without mana cost and cooldown
6111 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6113 // Inferno effect
6114 Charmed->CastSpell(Charmed, 22703, true, 0);
6118 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6119 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6120 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6121 This is why we use a half sec delay between the visual effect and the resurrection itself */
6122 void Spell::EffectSpiritHeal(uint32 /*i*/)
6125 if(!unitTarget || unitTarget->isAlive())
6126 return;
6127 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6128 return;
6129 if(!unitTarget->IsInWorld())
6130 return;
6132 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6133 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6134 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6135 ((Player*)unitTarget)->SpawnCorpseBones();
6139 // remove insignia spell effect
6140 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6142 sLog.outDebug("Effect: SkinPlayerCorpse");
6143 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6144 return;
6146 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6149 void Spell::EffectStealBeneficialBuff(uint32 i)
6151 sLog.outDebug("Effect: StealBeneficialBuff");
6153 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6154 return;
6156 std::vector <Aura *> steal_list;
6157 // Create dispel mask by dispel type
6158 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6159 Unit::AuraMap const& auras = unitTarget->GetAuras();
6160 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6162 Aura *aur = (*itr).second;
6163 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6165 // Need check for passive? this
6166 if (aur->IsPositive() && !aur->IsPassive())
6167 steal_list.push_back(aur);
6170 // Ok if exist some buffs for dispel try dispel it
6171 if (!steal_list.empty())
6173 std::list < std::pair<uint32,uint64> > success_list;
6174 int32 list_size = steal_list.size();
6175 // Dispell N = damage buffs (or while exist buffs for dispel)
6176 for (int32 count=0; count < damage && list_size > 0; ++count)
6178 // Random select buff for dispel
6179 Aura *aur = steal_list[urand(0, list_size-1)];
6180 // Not use chance for steal
6181 // TODO possible need do it
6182 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6184 // Remove buff from list for prevent doubles
6185 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6187 Aura *stealed = *j;
6188 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6190 j = steal_list.erase(j);
6191 --list_size;
6193 else
6194 ++j;
6197 // Really try steal and send log
6198 if (!success_list.empty())
6200 int32 count = success_list.size();
6201 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6202 data.append(unitTarget->GetPackGUID()); // Victim GUID
6203 data.append(m_caster->GetPackGUID()); // Caster GUID
6204 data << uint32(m_spellInfo->Id); // Dispell spell id
6205 data << uint8(0); // not used
6206 data << uint32(count); // count
6207 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6209 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6210 data << uint32(spellInfo->Id); // Spell Id
6211 data << uint8(0); // 0 - steals !=0 transfers
6212 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6214 m_caster->SendMessageToSet(&data, true);
6219 void Spell::EffectKillCredit(uint32 i)
6221 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6222 return;
6224 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6227 void Spell::EffectQuestFail(uint32 i)
6229 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6230 return;
6232 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);