[6982] Implemented gmlevel-based command security
[getmangos.git] / src / game / SpellEffects.cpp
blobe50423662dc6da7d50499a3cde7a698f0a6273f0
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
52 #include "Language.h"
53 #include "SocialMgr.h"
54 #include "Util.h"
55 #include "TemporarySummon.h"
56 #include "ScriptCalls.h"
58 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
60 &Spell::EffectNULL, // 0
61 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
62 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
63 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
64 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
65 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
66 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
67 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
68 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
69 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
70 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
71 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
72 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
73 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
74 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
75 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
76 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
77 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
78 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
79 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
80 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
81 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
82 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
83 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
84 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
85 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
86 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
87 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
88 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
89 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
90 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
91 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
92 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
93 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
94 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
95 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
96 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
97 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
98 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
99 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
100 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
101 &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
102 &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
103 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
104 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
105 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
106 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
107 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
108 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
109 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
110 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
111 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
112 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
113 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
114 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
115 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
116 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
117 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
118 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
119 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
120 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
121 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
122 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
123 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
124 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
125 &Spell::EffectApplyAreaAura, // 65 SPELL_EFFECT_APPLY_AREA_AURA_RAID
126 &Spell::EffectUnused, // 66 SPELL_EFFECT_CREATE_MANA_GEM (possibly recharge it, misc - is item ID)
127 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
128 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
129 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
130 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
131 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
132 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
133 &Spell::EffectUnused, // 73 SPELL_EFFECT_UNTRAIN_TALENTS
134 &Spell::EffectApplyGlyph, // 74 SPELL_EFFECT_APPLY_GLYPH
135 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
136 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
137 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
138 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
139 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
140 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
141 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
142 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
143 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
144 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
145 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
146 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
147 &Spell::EffectUnused, // 87 SPELL_EFFECT_WMO_DAMAGE
148 &Spell::EffectUnused, // 88 SPELL_EFFECT_WMO_REPAIR
149 &Spell::EffectUnused, // 89 SPELL_EFFECT_WMO_CHANGE
150 &Spell::EffectUnused, // 90 SPELL_EFFECT_KILL_CREDIT
151 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
152 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
153 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
154 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
155 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
156 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
157 &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
158 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
159 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
160 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
161 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
162 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
163 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
164 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
165 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
166 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
167 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
168 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
169 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
170 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
171 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
172 &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
173 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
174 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
175 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
176 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
177 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
178 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
179 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
180 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
181 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
182 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
183 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
184 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
185 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
186 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
187 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
188 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
189 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
190 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
191 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
192 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc)
193 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
194 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
195 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
196 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
197 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
198 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
199 &Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
200 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
201 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
202 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
203 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
204 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
205 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
206 &Spell::EffectActivateRune, //146 SPELL_EFFECT_ACTIVATE_RUNE
207 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
208 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
209 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
210 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
211 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
212 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
213 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
214 &Spell::EffectNULL, //154 unused
215 &Spell::EffectTitanGrip, //155 SPELL_EFFECT_TITAN_GRIP Allows you to equip two-handed axes, maces and swords in one hand, but you attack $49152s1% slower than normal.
216 &Spell::EffectNULL, //156 Add Socket
217 &Spell::EffectNULL, //157 create/learn random item/spell for profession
218 &Spell::EffectMilling, //158 milling
219 &Spell::EffectNULL //159 allow rename pet once again
222 void Spell::EffectNULL(uint32 /*i*/)
224 sLog.outDebug("WORLD: Spell Effect DUMMY");
227 void Spell::EffectUnused(uint32 /*i*/)
229 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
232 void Spell::EffectResurrectNew(uint32 i)
234 if(!unitTarget || unitTarget->isAlive())
235 return;
237 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
238 return;
240 if(!unitTarget->IsInWorld())
241 return;
243 Player* pTarget = ((Player*)unitTarget);
245 if(pTarget->isRessurectRequested()) // already have one active request
246 return;
248 uint32 health = damage;
249 uint32 mana = m_spellInfo->EffectMiscValue[i];
250 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
251 SendResurrectRequest(pTarget);
254 void Spell::EffectInstaKill(uint32 /*i*/)
256 if( !unitTarget || !unitTarget->isAlive() )
257 return;
259 // Demonic Sacrifice
260 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
262 uint32 entry = unitTarget->GetEntry();
263 uint32 spellID;
264 switch(entry)
266 case 416: spellID=18789; break; //imp
267 case 417: spellID=18792; break; //fellhunter
268 case 1860: spellID=18790; break; //void
269 case 1863: spellID=18791; break; //succubus
270 case 17252: spellID=35701; break; //fellguard
271 default:
272 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
273 return;
276 m_caster->CastSpell(m_caster,spellID,true);
279 if(m_caster==unitTarget) // prevent interrupt message
280 finish();
282 uint32 health = unitTarget->GetHealth();
283 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
286 void Spell::EffectEnvirinmentalDMG(uint32 i)
288 uint32 absorb = 0;
289 uint32 resist = 0;
291 // Note: this hack with damage replace required until GO casting not implemented
292 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
293 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
294 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
296 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
298 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
299 if(m_caster->GetTypeId() == TYPEID_PLAYER)
300 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
303 void Spell::EffectSchoolDMG(uint32 effect_idx)
305 if( unitTarget && unitTarget->isAlive())
307 switch(m_spellInfo->SpellFamilyName)
309 case SPELLFAMILY_GENERIC:
311 //Gore
312 if(m_spellInfo->SpellIconID == 2269 )
314 damage+= rand()%2 ? damage : 0;
317 switch(m_spellInfo->Id) // better way to check unknown
319 // Meteor like spells (divided damage to targets)
320 case 24340: case 26558: case 28884: // Meteor
321 case 36837: case 38903: case 41276: // Meteor
322 case 26789: // Shard of the Fallen Star
323 case 31436: // Malevolent Cleave
324 case 35181: // Dive Bomb
325 case 40810: case 43267: case 43268: // Saber Lash
326 case 42384: // Brutal Swipe
327 case 45150: // Meteor Slash
329 uint32 count = 0;
330 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
331 if(ihit->effectMask & (1<<effect_idx))
332 ++count;
334 damage /= count; // divide to all targets
335 break;
337 // percent from health with min
338 case 25599: // Thundercrash
340 damage = unitTarget->GetHealth() / 2;
341 if(damage < 200)
342 damage = 200;
343 break;
345 // Intercept (warrior spell trigger)
346 case 20253:
347 case 61491:
349 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.12f);
350 break;
353 break;
356 case SPELLFAMILY_MAGE:
358 // Arcane Blast
359 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
361 m_caster->CastSpell(m_caster,36032,true);
363 break;
365 case SPELLFAMILY_WARRIOR:
367 // Bloodthirst
368 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
370 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
372 // Shield Slam
373 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
374 damage += int32(m_caster->GetShieldBlockValue());
375 // Victory Rush
376 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
378 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
379 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
381 // Revenge ${$m1+$AP*0.207} to ${$M1+$AP*0.207}
382 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000400LL)
383 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.207f);
384 // Heroic Throw ${$m1+$AP*.50}
385 else if(m_spellInfo->SpellFamilyFlags & 0x0000000100000000LL)
386 damage+= uint32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f);
387 break;
389 case SPELLFAMILY_WARLOCK:
391 // Incinerate Rank 1 & 2
392 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
394 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
395 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
396 damage += int32(damage*0.25f);
398 break;
400 case SPELLFAMILY_PRIEST:
402 // Shadow Word: Death - deals damage equal to damage done to caster
403 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
404 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
405 break;
407 case SPELLFAMILY_DRUID:
409 // Ferocious Bite
410 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
412 // converts each extra point of energy into ($f1+$AP/410) additional damage
413 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
414 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
415 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
416 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
417 m_caster->SetPower(POWER_ENERGY,0);
419 // Rake
420 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
422 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
424 // Swipe
425 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
427 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
429 // Starfire
430 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
432 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
433 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
435 // Starfire Bonus (caster)
436 switch((*i)->GetModifier()->m_miscvalue)
438 case 5481: // Nordrassil Regalia - bonus
440 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
441 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
443 // Moonfire or Insect Swarm (target debuff from any casters)
444 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
446 int32 mod = (*i)->GetModifier()->m_amount;
447 damage += damage*mod/100;
448 break;
451 break;
453 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
455 damage += (*i)->GetModifier()->m_amount;
456 break;
461 //Mangle Bonus for the initial damage of Lacerate and Rake
462 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
463 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
465 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
466 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
467 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
469 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
470 break;
473 break;
475 case SPELLFAMILY_ROGUE:
477 // Envenom
478 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
480 // consume from stack dozes not more that have combo-points
481 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
483 // count consumed deadly poison doses at target
484 uint32 doses = 0;
486 // remove consumed poison doses
487 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
488 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
490 // Deadly poison (only attacker applied)
491 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
492 (*itr)->GetSpellProto()->SpellVisual[0]==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
494 --combo;
495 ++doses;
497 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
499 itr = auras.begin();
501 else
502 ++itr;
505 damage *= doses;
506 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
508 // Eviscerate and Envenom Bonus Damage (item set effect)
509 if(m_caster->GetDummyAura(37169))
510 damage += ((Player*)m_caster)->GetComboPoints()*40;
513 // Eviscerate
514 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
516 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
518 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
519 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
521 // Eviscerate and Envenom Bonus Damage (item set effect)
522 if(m_caster->GetDummyAura(37169))
523 damage += combo*40;
526 // Gouge
527 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
529 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.02f);
531 // Instant Poison
532 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
534 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
536 // Wound Poison
537 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
539 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
541 break;
543 case SPELLFAMILY_HUNTER:
545 // Mongoose Bite
546 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
548 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
550 // Counterattack
551 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
553 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
555 // Arcane Shot
556 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
558 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
560 // Steady Shot
561 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
563 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
564 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
566 // Explosive Trap Effect
567 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
569 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
571 break;
573 case SPELLFAMILY_PALADIN:
575 // Judgement of Vengeance
576 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
578 uint32 stacks = 0;
579 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
580 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
581 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
582 ++stacks;
583 if(!stacks)
584 //No damage if the target isn't affected by this
585 damage = -1;
586 else
587 damage *= stacks;
589 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP)
590 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
592 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
593 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
594 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
595 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
597 // Exorcism ($m1+0.15*$SPH+0.15*$AP)
598 else if(m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
600 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
601 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
602 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
603 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
605 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP)
606 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
608 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
609 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
610 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
611 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
613 // Holy Wrath ($m1+0.07*$SPH+0.07*$AP)
614 else if(m_spellInfo->SpellFamilyFlags & 0x0020000000000000LL)
616 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
617 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
618 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
619 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
621 break;
625 if(damage >= 0)
626 m_damage+= damage;
630 void Spell::EffectDummy(uint32 i)
632 if(!unitTarget && !gameObjTarget && !itemTarget)
633 return;
635 // selection by spell family
636 switch(m_spellInfo->SpellFamilyName)
638 case SPELLFAMILY_GENERIC:
640 switch(m_spellInfo->Id )
642 case 8063: // Deviate Fish
644 if(m_caster->GetTypeId() != TYPEID_PLAYER)
645 return;
647 uint32 spell_id = 0;
648 switch(urand(1,5))
650 case 1: spell_id = 8064; break; // Sleepy
651 case 2: spell_id = 8065; break; // Invigorate
652 case 3: spell_id = 8066; break; // Shrink
653 case 4: spell_id = 8067; break; // Party Time!
654 case 5: spell_id = 8068; break; // Healthy Spirit
656 m_caster->CastSpell(m_caster,spell_id,true,NULL);
657 return;
659 case 8213: // Savory Deviate Delight
661 if(m_caster->GetTypeId() != TYPEID_PLAYER)
662 return;
664 uint32 spell_id = 0;
665 switch(urand(1,2))
667 // Flip Out - ninja
668 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
669 // Yaaarrrr - pirate
670 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
672 m_caster->CastSpell(m_caster,spell_id,true,NULL);
673 return;
675 case 8593: // Symbol of life (restore creature to life)
676 case 31225: // Shimmering Vessel (restore creature to life)
678 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
679 return;
680 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
681 return;
683 case 12162: // Deep wounds
684 case 12850: // (now good common check for this spells)
685 case 12868:
687 if(!unitTarget)
688 return;
690 float damage;
691 // DW should benefit of attack power, damage percent mods etc.
692 // TODO: check if using offhand damage is correct and if it should be divided by 2
693 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
694 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
695 else
696 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
698 switch (m_spellInfo->Id)
700 case 12850: damage *= 0.2f; break;
701 case 12162: damage *= 0.4f; break;
702 case 12868: damage *= 0.6f; break;
703 default:
704 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
705 return;
708 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
709 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
710 return;
712 case 12975: //Last Stand
714 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
715 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
716 return;
718 case 13120: // net-o-matic
720 if(!unitTarget)
721 return;
723 uint32 spell_id = 0;
725 uint32 roll = urand(0, 99);
727 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
728 spell_id = 16566;
729 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
730 spell_id = 13119;
731 else // normal root
732 spell_id = 13099;
734 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
735 return;
737 case 13567: // Dummy Trigger
739 // can be used for different aura triggering, so select by aura
740 if(!m_triggeredByAuraSpell || !unitTarget)
741 return;
743 switch(m_triggeredByAuraSpell->Id)
745 case 26467: // Persistent Shield
746 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
747 break;
748 default:
749 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
750 break;
752 return;
754 case 14185: // Preparation Rogue
756 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
757 return;
759 //immediately finishes the cooldown on certain Rogue abilities
760 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
761 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
763 uint32 classspell = itr->first;
764 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
766 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
768 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
770 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
771 data << uint32(classspell);
772 data << uint64(m_caster->GetGUID());
773 ((Player*)m_caster)->GetSession()->SendPacket(&data);
776 return;
778 case 15998: // Capture Worg Pup
779 case 29435: // Capture Female Kaliri Hatchling
781 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
782 return;
784 Creature* creatureTarget = (Creature*)unitTarget;
785 creatureTarget->setDeathState(JUST_DIED);
786 creatureTarget->RemoveCorpse();
787 creatureTarget->SetHealth(0); // just for nice GM-mode view
788 return;
790 case 16589: // Noggenfogger Elixir
792 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
793 return;
795 uint32 spell_id = 0;
796 switch(urand(1,3))
798 case 1: spell_id = 16595; break;
799 case 2: spell_id = 16593; break;
800 default:spell_id = 16591; break;
803 m_caster->CastSpell(m_caster,spell_id,true,NULL);
804 return;
806 case 17251: // Spirit Healer Res
808 if(!unitTarget || !m_originalCaster)
809 return;
811 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
813 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
814 data << unitTarget->GetGUID();
815 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
817 return;
819 case 17271: // Test Fetid Skull
821 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
822 return;
824 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
826 m_caster->CastSpell(m_caster,spell_id,true,NULL);
827 return;
829 case 20577: // Cannibalize
830 if (unitTarget)
831 m_caster->CastSpell(m_caster,20578,false,NULL);
832 return;
833 case 23019: // Crystal Prison Dummy DND
835 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
836 return;
838 Creature* creatureTarget = (Creature*)unitTarget;
839 if(creatureTarget->isPet())
840 return;
842 creatureTarget->setDeathState(JUST_DIED);
843 creatureTarget->RemoveCorpse();
844 creatureTarget->SetHealth(0); // just for nice GM-mode view
846 GameObject* pGameObj = new GameObject;
848 Map *map = creatureTarget->GetMap();
850 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
851 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
852 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
854 delete pGameObj;
855 return;
858 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
859 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
860 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
861 pGameObj->SetSpellId(m_spellInfo->Id);
863 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
864 map->Add(pGameObj);
866 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
867 data << uint64(pGameObj->GetGUID());
868 m_caster->SendMessageToSet(&data,true);
870 return;
872 case 23074: // Arc. Dragonling
873 if (!m_CastItem) return;
874 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
875 return;
876 case 23075: // Mithril Mechanical Dragonling
877 if (!m_CastItem) return;
878 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
879 return;
880 case 23076: // Mechanical Dragonling
881 if (!m_CastItem) return;
882 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
883 return;
884 case 23133: // Gnomish Battle Chicken
885 if (!m_CastItem) return;
886 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
887 return;
888 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
890 int32 r = irand(0, 119);
891 if ( r < 20 ) // 1/6 polymorph
892 m_caster->CastSpell(m_caster,23444,true);
893 else if ( r < 100 ) // 4/6 evil twin
894 m_caster->CastSpell(m_caster,23445,true);
895 else // 1/6 miss the target
896 m_caster->CastSpell(m_caster,36902,true);
897 return;
899 case 23453: // Ultrasafe Transporter: Gadgetzan
900 if ( roll_chance_i(50) ) // success
901 m_caster->CastSpell(m_caster,23441,true);
902 else // failure
903 m_caster->CastSpell(m_caster,23446,true);
904 return;
905 case 23645: // Hourglass Sand
906 m_caster->RemoveAurasDueToSpell(23170);
907 return;
908 case 23725: // Gift of Life (warrior bwl trinket)
909 m_caster->CastSpell(m_caster,23782,true);
910 m_caster->CastSpell(m_caster,23783,true);
911 return;
912 case 25860: // Reindeer Transformation
914 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
915 return;
917 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
918 float speed = m_caster->GetSpeedRate(MOVE_RUN);
920 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
922 //5 different spells used depending on mounted speed and if mount can fly or not
923 if (flyspeed >= 4.1f)
924 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
925 else if (flyspeed >= 3.8f)
926 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
927 else if (flyspeed >= 1.6f)
928 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
929 else if (speed >= 2.0f)
930 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
931 else
932 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
934 return;
936 //case 26074: // Holiday Cheer
937 // return; -- implemented at client side
938 case 28006: // Arcane Cloaking
940 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
941 m_caster->CastSpell(unitTarget,29294,true);
942 return;
944 case 28730: // Arcane Torrent (Mana)
946 int32 count = 0;
947 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
948 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
949 if ((*i)->GetId() == 28734)
950 ++count;
951 if (count)
953 m_caster->RemoveAurasDueToSpell(28734);
954 int32 bp = damage * count;
955 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
957 return;
959 case 29200: // Purify Helboar Meat
961 if( m_caster->GetTypeId() != TYPEID_PLAYER )
962 return;
964 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
966 m_caster->CastSpell(m_caster,spell_id,true,NULL);
967 return;
969 case 29858: // Soulshatter
970 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
971 m_caster->CastSpell(unitTarget,32835,true);
972 return;
973 case 30458: // Nigh Invulnerability
974 if (!m_CastItem) return;
975 if(roll_chance_i(86)) // success
976 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
977 else // backfire in 14% casts
978 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
979 return;
980 case 30507: // Poultryizer
981 if (!m_CastItem) return;
982 if(roll_chance_i(80)) // success
983 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
984 else // backfire 20%
985 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
986 return;
987 case 33060: // Make a Wish
989 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
990 return;
992 uint32 spell_id = 0;
994 switch(urand(1,5))
996 case 1: spell_id = 33053; break;
997 case 2: spell_id = 33057; break;
998 case 3: spell_id = 33059; break;
999 case 4: spell_id = 33062; break;
1000 case 5: spell_id = 33064; break;
1003 m_caster->CastSpell(m_caster,spell_id,true,NULL);
1004 return;
1006 case 35745:
1008 uint32 spell_id;
1009 switch(m_caster->GetAreaId())
1011 case 3900: spell_id = 35743; break;
1012 case 3742: spell_id = 35744; break;
1013 default: return;
1016 m_caster->CastSpell(m_caster,spell_id,true);
1017 return;
1019 case 37674: // Chaos Blast
1021 if(!unitTarget)
1022 return;
1024 int32 basepoints0 = 100;
1025 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
1026 return;
1028 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
1030 // selecting one from Bloodstained Fortune item
1031 uint32 newitemid;
1032 switch(urand(1,20))
1034 case 1: newitemid = 32688; break;
1035 case 2: newitemid = 32689; break;
1036 case 3: newitemid = 32690; break;
1037 case 4: newitemid = 32691; break;
1038 case 5: newitemid = 32692; break;
1039 case 6: newitemid = 32693; break;
1040 case 7: newitemid = 32700; break;
1041 case 8: newitemid = 32701; break;
1042 case 9: newitemid = 32702; break;
1043 case 10: newitemid = 32703; break;
1044 case 11: newitemid = 32704; break;
1045 case 12: newitemid = 32705; break;
1046 case 13: newitemid = 32706; break;
1047 case 14: newitemid = 32707; break;
1048 case 15: newitemid = 32708; break;
1049 case 16: newitemid = 32709; break;
1050 case 17: newitemid = 32710; break;
1051 case 18: newitemid = 32711; break;
1052 case 19: newitemid = 32712; break;
1053 case 20: newitemid = 32713; break;
1054 default:
1055 return;
1058 DoCreateItem(i,newitemid);
1059 return;
1061 // Demon Broiled Surprise
1062 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1063 case 43723:
1065 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1066 return;
1068 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1069 return;
1072 case 44875: // Complete Raptor Capture
1074 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1075 return;
1077 Creature* creatureTarget = (Creature*)unitTarget;
1079 creatureTarget->setDeathState(JUST_DIED);
1080 creatureTarget->RemoveCorpse();
1081 creatureTarget->SetHealth(0); // just for nice GM-mode view
1083 //cast spell Raptor Capture Credit
1084 m_caster->CastSpell(m_caster,42337,true,NULL);
1085 return;
1087 case 37573: //Temporal Phase Modulator
1089 if(!unitTarget)
1090 return;
1092 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1093 if(!tempSummon)
1094 return;
1096 uint32 health = tempSummon->GetHealth();
1097 const uint32 entry_list[6] = {21821, 21820, 21817};
1099 float x = tempSummon->GetPositionX();
1100 float y = tempSummon->GetPositionY();
1101 float z = tempSummon->GetPositionZ();
1102 float o = tempSummon->GetOrientation();
1104 tempSummon->UnSummon();
1106 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1107 if (!pCreature)
1108 return;
1110 pCreature->SetHealth(health);
1112 if(pCreature->AI())
1113 pCreature->AI()->AttackStart(m_caster);
1115 return;
1117 case 34665: //Administer Antidote
1119 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1120 return;
1122 if(!unitTarget)
1123 return;
1125 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1126 if(!tempSummon)
1127 return;
1129 uint32 health = tempSummon->GetHealth();
1131 float x = tempSummon->GetPositionX();
1132 float y = tempSummon->GetPositionY();
1133 float z = tempSummon->GetPositionZ();
1134 float o = tempSummon->GetOrientation();
1135 tempSummon->UnSummon();
1137 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1138 if (!pCreature)
1139 return;
1141 pCreature->SetHealth(health);
1142 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1144 if (pCreature->AI())
1145 pCreature->AI()->AttackStart(m_caster);
1147 return;
1149 case 44997: // Converting Sentry
1151 //Converted Sentry Credit
1152 m_caster->CastSpell(m_caster, 45009, true);
1153 return;
1155 case 45030: // Impale Emissary
1157 // Emissary of Hate Credit
1158 m_caster->CastSpell(m_caster, 45088, true);
1159 return;
1161 case 50243: // Teach Language
1163 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1164 return;
1166 // spell has a 1/3 chance to trigger one of the below
1167 if(roll_chance_i(66))
1168 return;
1169 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1171 // 1000001 - gnomish binary
1172 m_caster->CastSpell(m_caster, 50242, true);
1174 else
1176 // 01001000 - goblin binary
1177 m_caster->CastSpell(m_caster, 50246, true);
1180 return;
1182 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1184 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1185 return;
1187 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1188 bg->EventPlayerDroppedFlag((Player*)m_caster);
1190 m_caster->CastSpell(m_caster, 30452, true, NULL);
1191 return;
1193 case 53341:
1194 case 53343:
1196 m_caster->CastSpell(m_caster,54586,true);
1197 return;
1201 //All IconID Check in there
1202 switch(m_spellInfo->SpellIconID)
1204 // Berserking (troll racial traits)
1205 case 1661:
1207 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1208 int32 melee_mod = 10;
1209 if (healthPerc <= 40)
1210 melee_mod = 30;
1211 if (healthPerc < 100 && healthPerc > 40)
1212 melee_mod = 10+(100-healthPerc)/3;
1214 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1215 int32 hasteModBasePoints1 = (5-melee_mod);
1216 int32 hasteModBasePoints2 = 5;
1218 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1219 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1220 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1221 return;
1224 break;
1226 case SPELLFAMILY_MAGE:
1227 switch(m_spellInfo->Id )
1229 case 11958: // Cold Snap
1231 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1232 return;
1234 // immediately finishes the cooldown on Frost spells
1235 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1236 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1238 if (itr->second->state == PLAYERSPELL_REMOVED)
1239 continue;
1241 uint32 classspell = itr->first;
1242 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1244 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1245 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1246 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1248 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1250 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1251 data << uint32(classspell);
1252 data << uint64(m_caster->GetGUID());
1253 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1256 return;
1258 case 32826:
1260 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1262 //Polymorph Cast Visual Rank 1
1263 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1264 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1266 return;
1269 break;
1270 case SPELLFAMILY_WARRIOR:
1271 // Charge
1272 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1274 int32 chargeBasePoints0 = damage;
1275 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1276 return;
1278 // Execute
1279 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1281 if(!unitTarget)
1282 return;
1284 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1285 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1286 m_caster->SetPower(POWER_RAGE,0);
1287 return;
1289 if(m_spellInfo->Id==21977) //Warrior's Wrath
1291 if(!unitTarget)
1292 return;
1294 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1295 return;
1297 break;
1298 case SPELLFAMILY_WARLOCK:
1299 //Life Tap (only it have this with dummy effect)
1300 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1302 float cost = m_currentBasePoints[0]+1;
1304 if(Player* modOwner = m_caster->GetSpellModOwner())
1305 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1307 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1309 if(int32(m_caster->GetHealth()) > dmg)
1311 // Shouldn't Appear in Combat Log
1312 m_caster->ModifyHealth(-dmg);
1314 int32 mana = dmg;
1316 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1317 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1319 // only Imp. Life Tap have this in combination with dummy aura
1320 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1321 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1324 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1326 // Mana Feed
1327 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1328 manaFeedVal = manaFeedVal * mana / 100;
1329 if(manaFeedVal > 0)
1330 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1332 else
1333 SendCastResult(SPELL_FAILED_FIZZLE);
1334 return;
1336 break;
1337 case SPELLFAMILY_PRIEST:
1338 switch(m_spellInfo->Id )
1340 case 28598: // Touch of Weakness triggered spell
1342 if(!unitTarget || !m_triggeredByAuraSpell)
1343 return;
1345 uint32 spellid = 0;
1346 switch(m_triggeredByAuraSpell->Id)
1348 case 2652: spellid = 2943; break; // Rank 1
1349 case 19261: spellid = 19249; break; // Rank 2
1350 case 19262: spellid = 19251; break; // Rank 3
1351 case 19264: spellid = 19252; break; // Rank 4
1352 case 19265: spellid = 19253; break; // Rank 5
1353 case 19266: spellid = 19254; break; // Rank 6
1354 case 25461: spellid = 25460; break; // Rank 7
1355 default:
1356 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1357 return;
1359 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1360 return;
1363 break;
1364 case SPELLFAMILY_DRUID:
1365 switch(m_spellInfo->Id )
1367 case 5420: // Tree of Life passive
1369 // Tree of Life area effect
1370 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1371 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1372 return;
1375 break;
1376 case SPELLFAMILY_ROGUE:
1377 switch(m_spellInfo->Id )
1379 case 31231: // Cheat Death
1381 m_caster->CastSpell(m_caster,45182,true);
1382 return;
1384 case 5938: // Shiv
1386 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1387 return;
1389 Player *pCaster = ((Player*)m_caster);
1391 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1392 if(!item)
1393 return;
1395 // all poison enchantments is temporary
1396 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1397 if(!enchant_id)
1398 return;
1400 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1401 if(!pEnchant)
1402 return;
1404 for (int s=0;s<3;s++)
1406 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1407 continue;
1409 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1410 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1411 continue;
1413 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1416 m_caster->CastSpell(unitTarget, 5940, true);
1417 return;
1420 break;
1421 case SPELLFAMILY_HUNTER:
1422 // Steady Shot
1423 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1425 if( !unitTarget || !unitTarget->isAlive())
1426 return;
1428 bool found = false;
1430 // check dazed affect
1431 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1432 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1434 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1436 found = true;
1437 break;
1441 if(found)
1442 m_damage+= damage;
1443 return;
1445 // Kill command
1446 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1448 if(m_caster->getClass()!=CLASS_HUNTER)
1449 return;
1451 // clear hunter crit aura state
1452 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1454 // additional damage from pet to pet target
1455 Pet* pet = m_caster->GetPet();
1456 if(!pet || !pet->getVictim())
1457 return;
1459 uint32 spell_id = 0;
1460 switch (m_spellInfo->Id)
1462 case 34026: spell_id = 34027; break; // rank 1
1463 default:
1464 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1465 return;
1468 pet->CastSpell(pet->getVictim(), spell_id, true);
1469 return;
1472 switch(m_spellInfo->Id)
1474 case 23989: //Readiness talent
1476 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1477 return;
1479 //immediately finishes the cooldown for hunter abilities
1480 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1481 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1483 uint32 classspell = itr->first;
1484 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1486 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1488 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1490 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1491 data << uint32(classspell);
1492 data << uint64(m_caster->GetGUID());
1493 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1496 return;
1498 case 37506: // Scatter Shot
1500 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1501 return;
1503 // break Auto Shot and autohit
1504 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1505 m_caster->AttackStop();
1506 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1507 return;
1510 break;
1511 case SPELLFAMILY_PALADIN:
1512 switch(m_spellInfo->SpellIconID)
1514 case 156: // Holy Shock
1516 if(!unitTarget)
1517 return;
1519 int hurt = 0;
1520 int heal = 0;
1522 switch(m_spellInfo->Id)
1524 case 20473: hurt = 25912; heal = 25914; break;
1525 case 20929: hurt = 25911; heal = 25913; break;
1526 case 20930: hurt = 25902; heal = 25903; break;
1527 case 27174: hurt = 27176; heal = 27175; break;
1528 case 33072: hurt = 33073; heal = 33074; break;
1529 default:
1530 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1531 return;
1534 if(m_caster->IsFriendlyTo(unitTarget))
1535 m_caster->CastSpell(unitTarget, heal, true, 0);
1536 else
1537 m_caster->CastSpell(unitTarget, hurt, true, 0);
1539 return;
1541 case 561: // Judgement of command
1543 if(!unitTarget)
1544 return;
1546 uint32 spell_id = m_currentBasePoints[i]+1;
1547 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1548 if(!spell_proto)
1549 return;
1551 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1553 // decreased damage (/2) for non-stunned target.
1554 SpellModifier *mod = new SpellModifier;
1555 mod->op = SPELLMOD_DAMAGE;
1556 mod->value = -50;
1557 mod->type = SPELLMOD_PCT;
1558 mod->spellId = m_spellInfo->Id;
1559 mod->mask = 0x0000020000000000LL;
1560 mod->mask2= 0LL;
1562 ((Player*)m_caster)->AddSpellMod(mod, true);
1563 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1564 // mod deleted
1565 ((Player*)m_caster)->AddSpellMod(mod, false);
1567 else
1568 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1570 return;
1574 switch(m_spellInfo->Id)
1576 case 31789: // Righteous Defense (step 1)
1578 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1580 // non-standard cast requirement check
1581 if (!unitTarget || unitTarget->getAttackers().empty())
1583 // clear cooldown at fail
1584 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1586 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1588 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1589 data << uint32(m_spellInfo->Id);
1590 data << uint64(m_caster->GetGUID());
1591 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1594 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1595 return;
1598 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1599 // Clear targets for eff 1
1600 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1601 ihit->effectMask &= ~(1<<1);
1603 // not empty (checked)
1604 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1606 // chance to be selected from list
1607 float chance = 100.0f/attackers.size();
1608 uint32 count=0;
1609 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1611 if(!roll_chance_f(chance))
1612 continue;
1613 ++count;
1614 AddUnitTarget((*aItr), 1);
1617 // now let next effect cast spell at each target.
1618 return;
1620 case 37877: // Blessing of Faith
1622 if(!unitTarget)
1623 return;
1625 uint32 spell_id = 0;
1626 switch(unitTarget->getClass())
1628 case CLASS_DRUID: spell_id = 37878; break;
1629 case CLASS_PALADIN: spell_id = 37879; break;
1630 case CLASS_PRIEST: spell_id = 37880; break;
1631 case CLASS_SHAMAN: spell_id = 37881; break;
1632 default: return; // ignore for not healing classes
1635 m_caster->CastSpell(m_caster,spell_id,true);
1636 return;
1639 break;
1640 case SPELLFAMILY_SHAMAN:
1641 //Shaman Rockbiter Weapon
1642 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1644 uint32 spell_id = 0;
1645 switch(m_spellInfo->Id)
1647 case 8017: spell_id = 36494; break; // Rank 1
1648 case 8018: spell_id = 36750; break; // Rank 2
1649 case 8019: spell_id = 36755; break; // Rank 3
1650 case 10399: spell_id = 36759; break; // Rank 4
1651 case 16314: spell_id = 36763; break; // Rank 5
1652 case 16315: spell_id = 36766; break; // Rank 6
1653 case 16316: spell_id = 36771; break; // Rank 7
1654 case 25479: spell_id = 36775; break; // Rank 8
1655 case 25485: spell_id = 36499; break; // Rank 9
1656 default:
1657 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1658 return;
1661 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1663 if(!spellInfo)
1665 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1666 return;
1669 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1670 return;
1672 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1674 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1676 if(item->IsFitToSpellRequirements(m_spellInfo))
1678 Spell *spell = new Spell(m_caster, spellInfo, true);
1680 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1681 // at calculation applied affect from Elemental Weapons talent
1682 // real enchantment damage-1
1683 spell->m_currentBasePoints[1] = damage-1;
1685 SpellCastTargets targets;
1686 targets.setItemTarget( item );
1687 spell->prepare(&targets);
1691 return;
1694 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1696 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1697 return;
1699 // Regenerate 6% of Total Mana Every 3 secs
1700 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1701 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1702 return;
1705 break;
1708 // pet auras
1709 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1711 m_caster->AddPetAura(petSpell);
1712 return;
1716 void Spell::EffectTriggerSpellWithValue(uint32 i)
1718 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1720 // normal case
1721 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1723 if(!spellInfo)
1725 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1726 return;
1729 int32 bp = damage;
1730 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1733 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1735 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1736 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1738 if(!spellInfo)
1740 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1741 return;
1744 finish();
1745 Spell *spell = new Spell(m_caster, spellInfo, true);
1747 SpellCastTargets targets;
1748 targets.setUnitTarget( unitTarget);
1749 spell->prepare(&targets);
1751 m_caster->SetCurrentCastedSpell(spell);
1752 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1756 void Spell::EffectForceCast(uint32 i)
1758 if( !unitTarget )
1759 return;
1761 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1763 // normal case
1764 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1766 if(!spellInfo)
1768 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1769 return;
1772 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1775 void Spell::EffectTriggerSpell(uint32 i)
1777 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1779 // special cases
1780 switch(triggered_spell_id)
1782 // Vanish
1783 case 18461:
1785 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1786 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1787 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1789 // if this spell is given to NPC it must handle rest by it's own AI
1790 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1791 return;
1793 // get highest rank of the Stealth spell
1794 uint32 spellId = 0;
1795 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1796 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1798 // only highest rank is shown in spell book, so simply check if shown in spell book
1799 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1800 continue;
1802 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1803 if (!spellInfo)
1804 continue;
1806 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1808 spellId = spellInfo->Id;
1809 break;
1813 // no Stealth spell found
1814 if (!spellId)
1815 return;
1817 // reset cooldown on it if needed
1818 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1819 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1821 m_caster->CastSpell(m_caster, spellId, true);
1822 return;
1824 // just skip
1825 case 23770: // Sayge's Dark Fortune of *
1826 // not exist, common cooldown can be implemented in scripts if need.
1827 return;
1828 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1829 case 29284:
1831 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1832 if (!spell)
1833 return;
1835 for (int i=0; i < spell->StackAmount; ++i)
1836 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1837 return;
1839 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1840 case 29286:
1842 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1843 if (!spell)
1844 return;
1846 for (int i=0; i < spell->StackAmount; ++i)
1847 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1848 return;
1850 // Righteous Defense
1851 case 31980:
1853 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1854 return;
1856 // Cloak of Shadows
1857 case 35729 :
1859 Unit::AuraMap& Auras = m_caster->GetAuras();
1860 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1862 // remove all harmful spells on you...
1863 if( // ignore positive and passive auras
1864 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1865 // ignore physical auras
1866 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1867 // ignore immunity persistent spells
1868 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1870 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1871 iter = Auras.begin();
1874 return;
1876 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1877 case 41967:
1879 if (Unit *pet = m_caster->GetPet())
1880 pet->CastSpell(pet, 28305, true);
1881 return;
1885 // normal case
1886 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1888 if(!spellInfo)
1890 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1891 return;
1894 // some triggered spells require specific equipment
1895 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1897 // main hand weapon required
1898 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1900 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1902 // skip spell if no weapon in slot or broken
1903 if(!item || item->IsBroken() )
1904 return;
1906 // skip spell if weapon not fit to triggered spell
1907 if(!item->IsFitToSpellRequirements(spellInfo))
1908 return;
1911 // offhand hand weapon required
1912 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1914 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1916 // skip spell if no weapon in slot or broken
1917 if(!item || item->IsBroken() )
1918 return;
1920 // skip spell if weapon not fit to triggered spell
1921 if(!item->IsFitToSpellRequirements(spellInfo))
1922 return;
1926 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1927 bool instant = false;
1928 for(uint32 j = i+1; j < 3; ++j)
1930 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1932 instant = true;
1933 break;
1937 if(instant)
1939 if (unitTarget)
1940 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1942 else
1943 m_TriggerSpells.push_back(spellInfo);
1946 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1948 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1950 // normal case
1951 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1953 if(!spellInfo)
1955 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1956 m_spellInfo->Id,effect_idx,triggered_spell_id);
1957 return;
1960 if (m_CastItem)
1961 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1963 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1965 SpellCastTargets targets;
1966 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1967 spell->m_CastItem = m_CastItem;
1968 spell->prepare(&targets, NULL);
1971 void Spell::EffectTeleportUnits(uint32 i)
1973 if(!unitTarget || unitTarget->isInFlight())
1974 return;
1976 switch (m_spellInfo->EffectImplicitTargetB[i])
1978 case TARGET_INNKEEPER_COORDINATES:
1980 // Only players can teleport to innkeeper
1981 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1982 return;
1984 ((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);
1985 return;
1987 case TARGET_TABLE_X_Y_Z_COORDINATES:
1989 // TODO: Only players can teleport?
1990 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1991 return;
1992 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1993 if(!st)
1995 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1996 return;
1998 ((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);
1999 break;
2001 case TARGET_BEHIND_VICTIM:
2003 // Get selected target for player (or victim for units)
2004 Unit *pTarget = NULL;
2005 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2006 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2007 else
2008 pTarget = m_caster->getVictim();
2009 // No target present - return
2010 if (!pTarget)
2011 return;
2012 // Init dest coordinates
2013 uint32 mapid = m_caster->GetMapId();
2014 float x = m_targets.m_destX;
2015 float y = m_targets.m_destY;
2016 float z = m_targets.m_destZ;
2017 float orientation = pTarget->GetOrientation();
2018 // Teleport
2019 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2020 ((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));
2021 else
2023 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2024 WorldPacket data;
2025 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2026 unitTarget->SendMessageToSet(&data, false);
2028 return;
2030 default:
2032 // If not exist data for dest location - return
2033 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2035 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2036 return;
2038 // Init dest coordinates
2039 uint32 mapid = m_caster->GetMapId();
2040 float x = m_targets.m_destX;
2041 float y = m_targets.m_destY;
2042 float z = m_targets.m_destZ;
2043 float orientation = unitTarget->GetOrientation();
2044 // Teleport
2045 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2046 ((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));
2047 else
2049 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2050 WorldPacket data;
2051 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2052 unitTarget->SendMessageToSet(&data, false);
2054 return;
2058 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2059 switch ( m_spellInfo->Id )
2061 // Dimensional Ripper - Everlook
2062 case 23442:
2064 int32 r = irand(0, 119);
2065 if ( r >= 70 ) // 7/12 success
2067 if ( r < 100 ) // 4/12 evil twin
2068 m_caster->CastSpell(m_caster,23445,true);
2069 else // 1/12 fire
2070 m_caster->CastSpell(m_caster,23449,true);
2072 return;
2074 // Ultrasafe Transporter: Toshley's Station
2075 case 36941:
2077 if ( roll_chance_i(50) ) // 50% success
2079 int32 rand_eff = urand(1,7);
2080 switch ( rand_eff )
2082 case 1:
2083 // soul split - evil
2084 m_caster->CastSpell(m_caster,36900,true);
2085 break;
2086 case 2:
2087 // soul split - good
2088 m_caster->CastSpell(m_caster,36901,true);
2089 break;
2090 case 3:
2091 // Increase the size
2092 m_caster->CastSpell(m_caster,36895,true);
2093 break;
2094 case 4:
2095 // Decrease the size
2096 m_caster->CastSpell(m_caster,36893,true);
2097 break;
2098 case 5:
2099 // Transform
2101 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2102 m_caster->CastSpell(m_caster,36897,true);
2103 else
2104 m_caster->CastSpell(m_caster,36899,true);
2105 break;
2107 case 6:
2108 // chicken
2109 m_caster->CastSpell(m_caster,36940,true);
2110 break;
2111 case 7:
2112 // evil twin
2113 m_caster->CastSpell(m_caster,23445,true);
2114 break;
2117 return;
2119 // Dimensional Ripper - Area 52
2120 case 36890:
2122 if ( roll_chance_i(50) ) // 50% success
2124 int32 rand_eff = urand(1,4);
2125 switch ( rand_eff )
2127 case 1:
2128 // soul split - evil
2129 m_caster->CastSpell(m_caster,36900,true);
2130 break;
2131 case 2:
2132 // soul split - good
2133 m_caster->CastSpell(m_caster,36901,true);
2134 break;
2135 case 3:
2136 // Increase the size
2137 m_caster->CastSpell(m_caster,36895,true);
2138 break;
2139 case 4:
2140 // Transform
2142 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2143 m_caster->CastSpell(m_caster,36897,true);
2144 else
2145 m_caster->CastSpell(m_caster,36899,true);
2146 break;
2150 return;
2155 void Spell::EffectApplyAura(uint32 i)
2157 if(!unitTarget)
2158 return;
2160 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2161 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2162 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2163 return;
2165 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2166 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2167 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2168 return;
2170 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2171 if(!caster)
2172 return;
2174 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2176 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2178 // Now Reduce spell duration using data received at spell hit
2179 int32 duration = Aur->GetAuraMaxDuration();
2180 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2181 Aur->setDiminishGroup(m_diminishGroup);
2183 // if Aura removed and deleted, do not continue.
2184 if(duration== 0 && !(Aur->IsPermanent()))
2186 delete Aur;
2187 return;
2190 if(duration != Aur->GetAuraMaxDuration())
2192 Aur->SetAuraMaxDuration(duration);
2193 Aur->SetAuraDuration(duration);
2196 bool added = unitTarget->AddAura(Aur);
2198 // Aura not added and deleted in AddAura call;
2199 if (!added)
2200 return;
2202 // found crash at character loading, broken pointer to Aur...
2203 // Aur was deleted in AddAura()...
2204 if(!Aur)
2205 return;
2207 // TODO Make a way so it works for every related spell!
2208 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2210 uint32 spellId = 0;
2211 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2212 spellId = 6788; // Weakened Soul
2213 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2214 spellId = 25771; // Forbearance
2215 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2216 spellId = 41425; // Hypothermia
2217 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2218 spellId = 11196; // Recently Bandaged
2219 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2220 spellId = 23230; // Blood Fury - Healing Reduction
2222 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2223 if (AdditionalSpellInfo)
2225 // applied at target by target
2226 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2227 unitTarget->AddAura(AdditionalAura);
2228 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2232 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2233 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2234 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2237 void Spell::EffectUnlearnSpecialization( uint32 i )
2239 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2240 return;
2242 Player *_player = (Player*)unitTarget;
2243 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2245 _player->removeSpell(spellToUnlearn);
2247 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2250 void Spell::EffectPowerDrain(uint32 i)
2252 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2253 return;
2255 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2257 if(!unitTarget)
2258 return;
2259 if(!unitTarget->isAlive())
2260 return;
2261 if(unitTarget->getPowerType() != drain_power)
2262 return;
2263 if(damage < 0)
2264 return;
2266 uint32 curPower = unitTarget->GetPower(drain_power);
2268 //add spell damage bonus
2269 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2271 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2272 uint32 power = damage;
2273 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2274 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2276 int32 new_damage;
2277 if(curPower < power)
2278 new_damage = curPower;
2279 else
2280 new_damage = power;
2282 unitTarget->ModifyPower(drain_power,-new_damage);
2284 if(drain_power == POWER_MANA)
2286 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2287 if(manaMultiplier==0)
2288 manaMultiplier = 1;
2290 if(Player *modOwner = m_caster->GetSpellModOwner())
2291 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2293 int32 gain = int32(new_damage*manaMultiplier);
2295 m_caster->ModifyPower(POWER_MANA,gain);
2296 //send log
2297 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2301 void Spell::EffectSendEvent(uint32 EffectIndex)
2303 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2305 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2306 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2308 switch(m_spellInfo->Id)
2310 case 23333: // Pickup Horde Flag
2311 /*do not uncomment .
2312 if(bg->GetTypeID()==BATTLEGROUND_WS)
2313 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2314 sLog.outDebug("Send Event Horde Flag Picked Up");
2315 break;
2316 /* not used :
2317 case 23334: // Drop Horde Flag
2318 if(bg->GetTypeID()==BATTLEGROUND_WS)
2319 bg->EventPlayerDroppedFlag((Player*)m_caster);
2320 sLog.outDebug("Drop Horde Flag");
2321 break;
2323 case 23335: // Pickup Alliance Flag
2324 /*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
2325 if(bg->GetTypeID()==BATTLEGROUND_WS)
2326 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2327 sLog.outDebug("Send Event Alliance Flag Picked Up");
2328 break;
2329 /* not used :
2330 case 23336: // Drop Alliance Flag
2331 if(bg->GetTypeID()==BATTLEGROUND_WS)
2332 bg->EventPlayerDroppedFlag((Player*)m_caster);
2333 sLog.outDebug("Drop Alliance Flag");
2334 break;
2335 case 23385: // Alliance Flag Returns
2336 if(bg->GetTypeID()==BATTLEGROUND_WS)
2337 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2338 sLog.outDebug("Alliance Flag Returned");
2339 break;
2340 case 23386: // Horde Flag Returns
2341 if(bg->GetTypeID()==BATTLEGROUND_WS)
2342 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2343 sLog.outDebug("Horde Flag Returned");
2344 break;*/
2345 case 34976:
2347 if(bg->GetTypeID()==BATTLEGROUND_EY)
2348 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2350 break;
2351 default:
2352 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2353 break;
2357 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2358 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2361 void Spell::EffectPowerBurn(uint32 i)
2363 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2364 return;
2366 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2368 if(!unitTarget)
2369 return;
2370 if(!unitTarget->isAlive())
2371 return;
2372 if(unitTarget->getPowerType()!=powertype)
2373 return;
2374 if(damage < 0)
2375 return;
2377 int32 curPower = int32(unitTarget->GetPower(powertype));
2379 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2380 uint32 power = damage;
2381 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2382 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2384 int32 new_damage = (curPower < power) ? curPower : power;
2386 unitTarget->ModifyPower(powertype,-new_damage);
2387 float multiplier = m_spellInfo->EffectMultipleValue[i];
2389 if(Player *modOwner = m_caster->GetSpellModOwner())
2390 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2392 new_damage = int32(new_damage*multiplier);
2393 m_damage+=new_damage;
2396 void Spell::EffectHeal( uint32 /*i*/ )
2398 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2400 // Try to get original caster
2401 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2403 // Skip if m_originalCaster not available
2404 if (!caster)
2405 return;
2407 int32 addhealth = damage;
2409 // Vessel of the Naaru (Vial of the Sunwell trinket)
2410 if (m_spellInfo->Id == 45064)
2412 // Amount of heal - depends from stacked Holy Energy
2413 int damageAmount = 0;
2414 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2415 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2416 if((*i)->GetId() == 45062)
2417 damageAmount+=(*i)->GetModifier()->m_amount;
2418 if (damageAmount)
2419 m_caster->RemoveAurasDueToSpell(45062);
2421 addhealth += damageAmount;
2423 // Swiftmend - consumes Regrowth or Rejuvenation
2424 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2426 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2427 // find most short by duration
2428 Aura *targetAura = NULL;
2429 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2431 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2432 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2434 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2435 targetAura = *i;
2439 if(!targetAura)
2441 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2442 return;
2444 int idx = 0;
2445 while(idx < 3)
2447 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2448 break;
2449 idx++;
2452 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2453 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2454 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2456 addhealth += tickheal * tickcount;
2458 else
2459 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2461 m_healing+=addhealth;
2465 void Spell::EffectHealPct( uint32 /*i*/ )
2467 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2469 // Try to get original caster
2470 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2472 // Skip if m_originalCaster not available
2473 if (!caster)
2474 return;
2476 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2477 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2479 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2480 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2482 if(caster->GetTypeId()==TYPEID_PLAYER)
2483 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2484 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2488 void Spell::EffectHealMechanical( uint32 /*i*/ )
2490 // Mechanic creature type should be correctly checked by targetCreatureType field
2491 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2493 // Try to get original caster
2494 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2496 // Skip if m_originalCaster not available
2497 if (!caster)
2498 return;
2500 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2501 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2502 unitTarget->ModifyHealth( int32(damage) );
2506 void Spell::EffectHealthLeech(uint32 i)
2508 if(!unitTarget)
2509 return;
2510 if(!unitTarget->isAlive())
2511 return;
2513 if(damage < 0)
2514 return;
2516 sLog.outDebug("HealthLeech :%i", damage);
2518 float multiplier = m_spellInfo->EffectMultipleValue[i];
2520 if(Player *modOwner = m_caster->GetSpellModOwner())
2521 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2523 int32 new_damage = int32(damage*multiplier);
2524 uint32 curHealth = unitTarget->GetHealth();
2525 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2526 if(curHealth < new_damage)
2527 new_damage = curHealth;
2529 if(m_caster->isAlive())
2531 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2533 m_caster->ModifyHealth(new_damage);
2535 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2536 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2538 // m_healthLeech+=tmpvalue;
2539 // m_damage+=new_damage;
2542 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2544 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2545 return;
2547 Player* player = (Player*)unitTarget;
2549 uint32 newitemid = itemtype;
2550 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2551 if(!pProto)
2553 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2554 return;
2557 uint32 num_to_add;
2559 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2560 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2562 int32 basePoints = m_currentBasePoints[i];
2563 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2564 if (randomPoints)
2565 num_to_add = basePoints + irand(1, randomPoints);
2566 else
2567 num_to_add = basePoints + 1;
2569 else if (pProto->MaxCount == 1)
2570 num_to_add = 1;
2571 else if(player->getLevel() >= m_spellInfo->spellLevel)
2573 int32 basePoints = m_currentBasePoints[i];
2574 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2575 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2577 else
2578 num_to_add = 2;
2580 if (num_to_add < 1)
2581 num_to_add = 1;
2582 if (num_to_add > pProto->Stackable)
2583 num_to_add = pProto->Stackable;
2585 // init items_count to 1, since 1 item will be created regardless of specialization
2586 int items_count=1;
2587 // the chance to create additional items
2588 float additionalCreateChance=0.0f;
2589 // the maximum number of created additional items
2590 uint8 additionalMaxNum=0;
2591 // get the chance and maximum number for creating extra items
2592 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2594 // roll with this chance till we roll not to create or we create the max num
2595 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2596 ++items_count;
2599 // really will be created more items
2600 num_to_add *= items_count;
2602 // can the player store the new item?
2603 ItemPosCountVec dest;
2604 uint32 no_space = 0;
2605 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2606 if( msg != EQUIP_ERR_OK )
2608 // convert to possible store amount
2609 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2610 num_to_add -= no_space;
2611 else
2613 // if not created by another reason from full inventory or unique items amount limitation
2614 player->SendEquipError( msg, NULL, NULL );
2615 return;
2619 if(num_to_add)
2621 // create the new item and store it
2622 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2624 // was it successful? return error if not
2625 if(!pItem)
2627 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2628 return;
2631 // set the "Crafted by ..." property of the item
2632 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2633 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2635 // send info to the client
2636 if(pItem)
2637 player->SendNewItem(pItem, num_to_add, true, true);
2639 // we succeeded in creating at least one item, so a levelup is possible
2640 player->UpdateCraftSkill(m_spellInfo->Id);
2643 // for battleground marks send by mail if not add all expected
2644 if(no_space > 0 )
2646 BattleGroundTypeId bgType;
2647 switch(m_spellInfo->Id)
2649 case SPELL_AV_MARK_WINNER:
2650 case SPELL_AV_MARK_LOSER:
2651 bgType = BATTLEGROUND_AV;
2652 break;
2653 case SPELL_WS_MARK_WINNER:
2654 case SPELL_WS_MARK_LOSER:
2655 bgType = BATTLEGROUND_WS;
2656 break;
2657 case SPELL_AB_MARK_WINNER:
2658 case SPELL_AB_MARK_LOSER:
2659 bgType = BATTLEGROUND_AB;
2660 break;
2661 default:
2662 return;
2665 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2666 bg->SendRewardMarkByMail(player,newitemid,no_space);
2670 void Spell::EffectCreateItem(uint32 i)
2672 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2675 void Spell::EffectPersistentAA(uint32 i)
2677 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2679 if(Player* modOwner = m_caster->GetSpellModOwner())
2680 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2682 int32 duration = GetSpellDuration(m_spellInfo);
2683 DynamicObject* dynObj = new DynamicObject;
2684 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))
2686 delete dynObj;
2687 return;
2689 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2690 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2691 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2692 m_caster->AddDynObject(dynObj);
2693 dynObj->GetMap()->Add(dynObj);
2696 void Spell::EffectEnergize(uint32 i)
2698 if(!unitTarget)
2699 return;
2700 if(!unitTarget->isAlive())
2701 return;
2703 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2704 return;
2706 // Some level depends spells
2707 int multiplier = 0;
2708 int level_diff = 0;
2709 switch (m_spellInfo->Id)
2711 // Restore Energy
2712 case 9512:
2713 level_diff = m_caster->getLevel() - 40;
2714 multiplier = 2;
2715 break;
2716 // Blood Fury
2717 case 24571:
2718 level_diff = m_caster->getLevel() - 60;
2719 multiplier = 10;
2720 break;
2721 // Burst of Energy
2722 case 24532:
2723 level_diff = m_caster->getLevel() - 60;
2724 multiplier = 4;
2725 break;
2726 default:
2727 break;
2730 if (level_diff > 0)
2731 damage -= multiplier * level_diff;
2733 if(damage < 0)
2734 return;
2736 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2738 if(unitTarget->GetMaxPower(power) == 0)
2739 return;
2741 unitTarget->ModifyPower(power,damage);
2742 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2744 // Mad Alchemist's Potion
2745 if (m_spellInfo->Id == 45051)
2747 // find elixirs on target
2748 uint32 elixir_mask = 0;
2749 Unit::AuraMap& Auras = unitTarget->GetAuras();
2750 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2752 uint32 spell_id = itr->second->GetId();
2753 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2754 elixir_mask |= mask;
2757 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2758 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2760 // get all available elixirs by mask and spell level
2761 std::vector<uint32> elixirs;
2762 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2763 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2765 if (itr->second & elixir_mask)
2767 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2768 continue;
2770 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2771 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2772 continue;
2774 elixirs.push_back(itr->first);
2778 if (!elixirs.empty())
2780 // cast random elixir on target
2781 uint32 rand_spell = urand(0,elixirs.size()-1);
2782 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2787 void Spell::EffectEnergisePct(uint32 i)
2789 if(!unitTarget)
2790 return;
2791 if(!unitTarget->isAlive())
2792 return;
2794 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2795 return;
2797 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2799 uint32 maxPower = unitTarget->GetMaxPower(power);
2800 if(maxPower == 0)
2801 return;
2803 uint32 gain = damage * maxPower / 100;
2804 unitTarget->ModifyPower(power, gain);
2805 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2808 void Spell::SendLoot(uint64 guid, LootType loottype)
2810 Player* player = (Player*)m_caster;
2811 if (!player)
2812 return;
2814 if (gameObjTarget)
2816 if (Script->GOHello(player, gameObjTarget))
2817 return;
2819 switch (gameObjTarget->GetGoType())
2821 case GAMEOBJECT_TYPE_DOOR:
2822 case GAMEOBJECT_TYPE_BUTTON:
2823 gameObjTarget->UseDoorOrButton();
2824 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2825 return;
2827 case GAMEOBJECT_TYPE_QUESTGIVER:
2828 // start or end quest
2829 player->PrepareQuestMenu(guid);
2830 player->SendPreparedQuest(guid);
2831 return;
2833 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2834 // triggering linked GO
2835 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2836 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2837 return;
2839 case GAMEOBJECT_TYPE_GOOBER:
2840 // goober_scripts can be triggered if the player don't have the quest
2841 if (gameObjTarget->GetGOInfo()->goober.eventId)
2843 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2844 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2847 // cast goober spell
2848 if (gameObjTarget->GetGOInfo()->goober.questId)
2849 ///Quest require to be active for GO using
2850 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2851 return;
2853 gameObjTarget->AddUniqueUse(player);
2854 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2856 //TODO? Objective counting called without spell check but with quest objective check
2857 // if send spell id then this line will duplicate to spell casting call (double counting)
2858 // So we or have this line and not required in quest_template have reqSpellIdN
2859 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2860 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2862 // triggering linked GO
2863 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2864 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2866 return;
2868 case GAMEOBJECT_TYPE_CHEST:
2869 // TODO: possible must be moved to loot release (in different from linked triggering)
2870 if (gameObjTarget->GetGOInfo()->chest.eventId)
2872 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2873 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2876 // triggering linked GO
2877 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2878 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2880 // Don't return, let loots been taken
2884 // Send loot
2885 player->SendLoot(guid, loottype);
2888 void Spell::EffectOpenLock(uint32 /*i*/)
2890 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2892 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2893 return;
2896 Player* player = (Player*)m_caster;
2898 LootType loottype = LOOT_CORPSE;
2899 uint32 lockId = 0;
2900 uint64 guid = 0;
2902 // Get lockId
2903 if(gameObjTarget)
2905 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2906 // Arathi Basin banner opening !
2907 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2908 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2910 //isAllowUseBattleGroundObject() already called in CanCast()
2911 // in battleground check
2912 if(BattleGround *bg = player->GetBattleGround())
2914 // check if it's correct bg
2915 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2916 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2917 return;
2920 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2922 //isAllowUseBattleGroundObject() already called in CanCast()
2923 // in battleground check
2924 if(BattleGround *bg = player->GetBattleGround())
2926 if(bg->GetTypeID() == BATTLEGROUND_EY)
2927 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2928 return;
2931 lockId = gameObjTarget->GetLockId();
2932 guid = gameObjTarget->GetGUID();
2934 else if(itemTarget)
2936 lockId = itemTarget->GetProto()->LockID;
2937 guid = itemTarget->GetGUID();
2939 else
2941 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2942 return;
2945 if(!lockId) // possible case for GO and maybe for items.
2947 SendLoot(guid, loottype);
2948 return;
2951 // Get LockInfo
2952 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2954 if (!lockInfo)
2956 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2957 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2958 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2959 return;
2962 // check key
2963 for(int i = 0; i < 8; ++i)
2965 // Type==1 This means lockInfo->Index[i] is an item
2966 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2968 SendLoot(guid, loottype);
2969 return;
2973 uint32 SkillId = 0;
2974 // Check and skill-up skill
2975 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2976 SkillId = m_spellInfo->EffectMiscValue[1];
2977 // pickpocketing spells
2978 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2979 SkillId = SKILL_LOCKPICKING;
2981 // skill bonus provided by casting spell (mostly item spells)
2982 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2984 uint32 reqSkillValue = lockInfo->Skill[0];
2986 if(lockInfo->Skill[1]) // required pick lock skill applying
2988 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2990 SendCastResult(SPELL_FAILED_FIZZLE);
2991 return;
2994 reqSkillValue = lockInfo->Skill[1];
2996 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2998 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2999 return;
3002 if ( SkillId )
3004 loottype = LOOT_SKINNING;
3005 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
3007 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3008 return;
3011 // update skill if really known
3012 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3013 if(SkillValue) // non only item base skill
3015 if(gameObjTarget)
3017 // Allow one skill-up until respawned
3018 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3019 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3020 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3022 else if(itemTarget)
3024 // Do one skill-up
3025 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3026 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3031 SendLoot(guid, loottype);
3034 void Spell::EffectSummonChangeItem(uint32 i)
3036 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3037 return;
3039 Player *player = (Player*)m_caster;
3041 // applied only to using item
3042 if(!m_CastItem)
3043 return;
3045 // ... only to item in own inventory/bank/equip_slot
3046 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3047 return;
3049 uint32 newitemid = m_spellInfo->EffectItemType[i];
3050 if(!newitemid)
3051 return;
3053 uint16 pos = m_CastItem->GetPos();
3055 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3056 if( !pNewItem )
3057 return;
3059 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3061 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3062 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3065 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3067 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3068 player->DurabilityLoss(pNewItem, loosePercent);
3071 if( player->IsInventoryPos( pos ) )
3073 ItemPosCountVec dest;
3074 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3075 if( msg == EQUIP_ERR_OK )
3077 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3079 // prevent crash at access and unexpected charges counting with item update queue corrupt
3080 if(m_CastItem==m_targets.getItemTarget())
3081 m_targets.setItemTarget(NULL);
3083 m_CastItem = NULL;
3085 player->StoreItem( dest, pNewItem, true);
3086 return;
3089 else if( player->IsBankPos ( pos ) )
3091 ItemPosCountVec dest;
3092 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3093 if( msg == EQUIP_ERR_OK )
3095 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3097 // prevent crash at access and unexpected charges counting with item update queue corrupt
3098 if(m_CastItem==m_targets.getItemTarget())
3099 m_targets.setItemTarget(NULL);
3101 m_CastItem = NULL;
3103 player->BankItem( dest, pNewItem, true);
3104 return;
3107 else if( player->IsEquipmentPos ( pos ) )
3109 uint16 dest;
3110 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3111 if( msg == EQUIP_ERR_OK )
3113 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3115 // prevent crash at access and unexpected charges counting with item update queue corrupt
3116 if(m_CastItem==m_targets.getItemTarget())
3117 m_targets.setItemTarget(NULL);
3119 m_CastItem = NULL;
3121 player->EquipItem( dest, pNewItem, true);
3122 player->AutoUnequipOffhandIfNeed();
3123 return;
3127 // fail
3128 delete pNewItem;
3131 void Spell::EffectOpenSecretSafe(uint32 i)
3133 EffectOpenLock(i); //no difference for now
3136 void Spell::EffectProficiency(uint32 /*i*/)
3138 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3139 return;
3140 Player *p_target = (Player*)unitTarget;
3142 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3143 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3145 p_target->AddWeaponProficiency(subClassMask);
3146 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3148 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3150 p_target->AddArmorProficiency(subClassMask);
3151 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3155 void Spell::EffectApplyAreaAura(uint32 i)
3157 if(!unitTarget)
3158 return;
3159 if(!unitTarget->isAlive())
3160 return;
3162 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3163 unitTarget->AddAura(Aur);
3166 void Spell::EffectSummonType(uint32 i)
3168 switch(m_spellInfo->EffectMiscValueB[i])
3170 case SUMMON_TYPE_GUARDIAN:
3171 case SUMMON_TYPE_POSESSED:
3172 case SUMMON_TYPE_POSESSED2:
3173 case SUMMON_TYPE_GUARDIAN2:
3174 EffectSummonGuardian(i);
3175 break;
3176 case SUMMON_TYPE_WILD:
3177 EffectSummonWild(i);
3178 break;
3179 case SUMMON_TYPE_DEMON:
3180 EffectSummonDemon(i);
3181 break;
3182 case SUMMON_TYPE_SUMMON:
3183 EffectSummon(i);
3184 break;
3185 case SUMMON_TYPE_CRITTER:
3186 case SUMMON_TYPE_CRITTER2:
3187 case SUMMON_TYPE_CRITTER3:
3188 EffectSummonCritter(i);
3189 break;
3190 case SUMMON_TYPE_TOTEM_SLOT1:
3191 case SUMMON_TYPE_TOTEM_SLOT2:
3192 case SUMMON_TYPE_TOTEM_SLOT3:
3193 case SUMMON_TYPE_TOTEM_SLOT4:
3194 case SUMMON_TYPE_TOTEM:
3195 EffectSummonTotem(i);
3196 break;
3197 case SUMMON_TYPE_UNKNOWN1:
3198 case SUMMON_TYPE_UNKNOWN2:
3199 case SUMMON_TYPE_UNKNOWN3:
3200 case SUMMON_TYPE_UNKNOWN4:
3201 case SUMMON_TYPE_UNKNOWN5:
3202 break;
3203 default:
3204 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3205 break;
3209 void Spell::EffectSummon(uint32 i)
3211 if(m_caster->GetPetGUID())
3212 return;
3214 if(!unitTarget)
3215 return;
3216 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3217 if(!pet_entry)
3218 return;
3219 uint32 level = m_caster->getLevel();
3220 Pet* spawnCreature = new Pet(SUMMON_PET);
3222 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3224 // set timer for unsummon
3225 int32 duration = GetSpellDuration(m_spellInfo);
3226 if(duration > 0)
3227 spawnCreature->SetDuration(duration);
3229 return;
3232 Map *map = m_caster->GetMap();
3233 uint32 pet_number = objmgr.GeneratePetNumber();
3234 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3236 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3237 delete spawnCreature;
3238 return;
3241 // Summon in dest location
3242 float x,y,z;
3243 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3245 x = m_targets.m_destX;
3246 y = m_targets.m_destY;
3247 z = m_targets.m_destZ;
3249 else
3250 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3252 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3254 if(!spawnCreature->IsPositionValid())
3256 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3257 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3258 delete spawnCreature;
3259 return;
3262 // set timer for unsummon
3263 int32 duration = GetSpellDuration(m_spellInfo);
3264 if(duration > 0)
3265 spawnCreature->SetDuration(duration);
3267 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3268 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3269 spawnCreature->setPowerType(POWER_MANA);
3270 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3271 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3272 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3273 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3274 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3275 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3276 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3277 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3278 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3280 spawnCreature->InitStatsForLevel(level);
3282 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3284 spawnCreature->AIM_Initialize();
3285 spawnCreature->InitPetCreateSpells();
3286 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3287 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3289 std::string name = m_caster->GetName();
3290 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3291 spawnCreature->SetName( name );
3293 map->Add((Creature*)spawnCreature);
3295 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3297 m_caster->SetPet(spawnCreature);
3298 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3299 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3300 ((Player*)m_caster)->PetSpellInitialize();
3304 void Spell::EffectLearnSpell(uint32 i)
3306 if(!unitTarget)
3307 return;
3309 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3311 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3312 EffectLearnPetSpell(i);
3314 return;
3317 Player *player = (Player*)unitTarget;
3319 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3320 player->learnSpell(spellToLearn);
3322 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3325 void Spell::EffectDispel(uint32 i)
3327 if(!unitTarget)
3328 return;
3330 // Fill possible dispell list
3331 std::vector <Aura *> dispel_list;
3333 // Create dispel mask by dispel type
3334 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3335 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3336 Unit::AuraMap const& auras = unitTarget->GetAuras();
3337 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3339 Aura *aur = (*itr).second;
3340 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3342 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3344 bool positive = true;
3345 if (!aur->IsPositive())
3346 positive = false;
3347 else
3348 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3350 // do not remove positive auras if friendly target
3351 // negative auras if non-friendly target
3352 if(positive == unitTarget->IsFriendlyTo(m_caster))
3353 continue;
3355 // Add aura to dispel list
3356 dispel_list.push_back(aur);
3359 // Ok if exist some buffs for dispel try dispel it
3360 if (!dispel_list.empty())
3362 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3363 std::list < uint32 > fail_list; // spell_id
3364 int32 list_size = dispel_list.size();
3365 // Dispell N = damage buffs (or while exist buffs for dispel)
3366 for (int32 count=0; count < damage && list_size > 0; ++count)
3368 // Random select buff for dispel
3369 Aura *aur = dispel_list[urand(0, list_size-1)];
3371 SpellEntry const* spellInfo = aur->GetSpellProto();
3372 // Base dispel chance
3373 // TODO: possible chance depend from spell level??
3374 int32 miss_chance = 0;
3375 // Apply dispel mod from aura caster
3376 if (Unit *caster = aur->GetCaster())
3378 if ( Player* modOwner = caster->GetSpellModOwner() )
3379 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3381 // Try dispel
3382 if (roll_chance_i(miss_chance))
3383 fail_list.push_back(aur->GetId());
3384 else
3385 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3386 // Remove buff from list for prevent doubles
3387 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3389 Aura *dispeled = *j;
3390 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3392 j = dispel_list.erase(j);
3393 --list_size;
3395 else
3396 ++j;
3399 // Send success log and really remove auras
3400 if (!success_list.empty())
3402 int32 count = success_list.size();
3403 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3404 data.append(unitTarget->GetPackGUID()); // Victim GUID
3405 data.append(m_caster->GetPackGUID()); // Caster GUID
3406 data << uint32(m_spellInfo->Id); // Dispell spell id
3407 data << uint8(0); // not used
3408 data << uint32(count); // count
3409 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3411 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3412 data << uint32(spellInfo->Id); // Spell Id
3413 data << uint8(0); // 0 - dispeled !=0 cleansed
3414 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3416 m_caster->SendMessageToSet(&data, true);
3418 // On succes dispel
3419 // Devour Magic
3420 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3422 uint32 heal_spell = 0;
3423 switch (m_spellInfo->Id)
3425 case 19505: heal_spell = 19658; break;
3426 case 19731: heal_spell = 19732; break;
3427 case 19734: heal_spell = 19733; break;
3428 case 19736: heal_spell = 19735; break;
3429 case 27276: heal_spell = 27278; break;
3430 case 27277: heal_spell = 27279; break;
3431 default:
3432 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3433 break;
3435 if (heal_spell)
3436 m_caster->CastSpell(m_caster, heal_spell, true);
3439 // Send fail log to client
3440 if (!fail_list.empty())
3442 // Failed to dispell
3443 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3444 data << uint64(m_caster->GetGUID()); // Caster GUID
3445 data << uint64(unitTarget->GetGUID()); // Victim GUID
3446 data << uint32(m_spellInfo->Id); // Dispell spell id
3447 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3448 data << uint32(*j); // Spell Id
3449 m_caster->SendMessageToSet(&data, true);
3454 void Spell::EffectDualWield(uint32 /*i*/)
3456 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3457 ((Player*)unitTarget)->SetCanDualWield(true);
3460 void Spell::EffectPull(uint32 /*i*/)
3462 // TODO: create a proper pull towards distract spell center for distract
3463 sLog.outDebug("WORLD: Spell Effect DUMMY");
3466 void Spell::EffectDistract(uint32 /*i*/)
3468 // Check for possible target
3469 if (!unitTarget || unitTarget->isInCombat())
3470 return;
3472 // target must be OK to do this
3473 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3474 return;
3476 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3478 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3480 // For players just turn them
3481 WorldPacket data;
3482 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3483 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3484 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3486 else
3488 // Set creature Distracted, Stop it, And turn it
3489 unitTarget->SetOrientation(angle);
3490 unitTarget->StopMoving();
3491 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3495 void Spell::EffectPickPocket(uint32 /*i*/)
3497 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3498 return;
3500 // victim must be creature and attackable
3501 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3502 return;
3504 // victim have to be alive and humanoid or undead
3505 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3507 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3509 if (chance > irand(0, 19))
3511 // Stealing successful
3512 //sLog.outDebug("Sending loot from pickpocket");
3513 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3515 else
3517 // Reveal action + get attack
3518 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3519 if (((Creature*)unitTarget)->AI())
3520 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3525 void Spell::EffectAddFarsight(uint32 i)
3527 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3528 int32 duration = GetSpellDuration(m_spellInfo);
3529 DynamicObject* dynObj = new DynamicObject;
3530 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))
3532 delete dynObj;
3533 return;
3535 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3536 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3537 m_caster->AddDynObject(dynObj);
3538 dynObj->GetMap()->Add(dynObj);
3539 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3540 ((Player*)m_caster)->SetFarSight(dynObj->GetGUID());
3543 void Spell::EffectSummonWild(uint32 i)
3545 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3546 if(!creature_entry)
3547 return;
3549 uint32 level = m_caster->getLevel();
3551 // level of creature summoned using engineering item based at engineering skill level
3552 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3554 ItemPrototype const *proto = m_CastItem->GetProto();
3555 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3557 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3558 if(skill202)
3560 level = skill202/5;
3565 // select center of summon position
3566 float center_x = m_targets.m_destX;
3567 float center_y = m_targets.m_destY;
3568 float center_z = m_targets.m_destZ;
3570 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3572 int32 amount = damage > 0 ? damage : 1;
3574 for(int32 count = 0; count < amount; ++count)
3576 float px, py, pz;
3577 // If dest location if present
3578 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3580 // Summon 1 unit in dest location
3581 if (count == 0)
3583 px = m_targets.m_destX;
3584 py = m_targets.m_destY;
3585 pz = m_targets.m_destZ;
3587 // Summon in random point all other units if location present
3588 else
3589 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3591 // Summon if dest location not present near caster
3592 else
3593 m_caster->GetClosePoint(px,py,pz,3.0f);
3595 int32 duration = GetSpellDuration(m_spellInfo);
3597 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3599 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3603 void Spell::EffectSummonGuardian(uint32 i)
3605 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3606 if(!pet_entry)
3607 return;
3609 // Jewelery statue case (totem like)
3610 if(m_spellInfo->SpellIconID==2056)
3612 EffectSummonTotem(i);
3613 return;
3616 // set timer for unsummon
3617 int32 duration = GetSpellDuration(m_spellInfo);
3619 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3620 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3621 // so this code hack in fact
3622 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3623 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3624 return; // find old guardian, ignore summon
3626 // in another case summon new
3627 uint32 level = m_caster->getLevel();
3629 // level of pet summoned using engineering item based at engineering skill level
3630 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3632 ItemPrototype const *proto = m_CastItem->GetProto();
3633 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3635 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3636 if(skill202)
3638 level = skill202/5;
3643 // select center of summon position
3644 float center_x = m_targets.m_destX;
3645 float center_y = m_targets.m_destY;
3646 float center_z = m_targets.m_destZ;
3648 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3650 int32 amount = damage > 0 ? damage : 1;
3652 for(int32 count = 0; count < amount; ++count)
3654 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3656 Map *map = m_caster->GetMap();
3657 uint32 pet_number = objmgr.GeneratePetNumber();
3658 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3660 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3661 delete spawnCreature;
3662 return;
3665 float px, py, pz;
3666 // If dest location if present
3667 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3669 // Summon 1 unit in dest location
3670 if (count == 0)
3672 px = m_targets.m_destX;
3673 py = m_targets.m_destY;
3674 pz = m_targets.m_destZ;
3676 // Summon in random point all other units if location present
3677 else
3678 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3680 // Summon if dest location not present near caster
3681 else
3682 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3684 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3686 if(!spawnCreature->IsPositionValid())
3688 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3689 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3690 delete spawnCreature;
3691 return;
3694 if(duration > 0)
3695 spawnCreature->SetDuration(duration);
3697 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3698 spawnCreature->setPowerType(POWER_MANA);
3699 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3700 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3701 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3702 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3703 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3704 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3705 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3707 spawnCreature->InitStatsForLevel(level);
3708 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3710 spawnCreature->AIM_Initialize();
3712 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3713 ((Player*)m_caster)->AddGuardian(spawnCreature);
3715 map->Add((Creature*)spawnCreature);
3719 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3721 if(!unitTarget)
3722 return;
3724 if(unitTarget->isInFlight())
3725 return;
3727 uint32 mapid = m_caster->GetMapId();
3728 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3730 float fx,fy,fz;
3731 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3733 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3734 ((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));
3735 else
3736 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3739 void Spell::EffectLearnSkill(uint32 i)
3741 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3742 return;
3744 if(damage < 0)
3745 return;
3747 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3748 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3749 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3752 void Spell::EffectAddHonor(uint32 /*i*/)
3754 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3755 return;
3757 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3759 // TODO: find formula for honor reward based on player's level!
3761 // now fixed only for level 70 players:
3762 if (((Player*)unitTarget)->getLevel() == 70)
3763 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3766 void Spell::EffectTradeSkill(uint32 /*i*/)
3768 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3769 return;
3770 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3771 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3772 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3775 void Spell::EffectEnchantItemPerm(uint32 i)
3777 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3778 return;
3779 if (!itemTarget)
3780 return;
3782 Player* p_caster = (Player*)m_caster;
3784 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3786 if (m_spellInfo->EffectMiscValue[i])
3788 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3790 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3791 if(!pEnchant)
3792 return;
3794 // item can be in trade slot and have owner diff. from caster
3795 Player* item_owner = itemTarget->GetOwner();
3796 if(!item_owner)
3797 return;
3799 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3801 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3802 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3803 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3804 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3807 // remove old enchanting before applying new if equipped
3808 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3810 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3812 // add new enchanting if equipped
3813 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3817 void Spell::EffectEnchantItemTmp(uint32 i)
3819 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3820 return;
3822 Player* p_caster = (Player*)m_caster;
3824 if(!itemTarget)
3825 return;
3827 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3829 // Shaman Rockbiter Weapon
3830 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3832 int32 enchnting_damage = m_currentBasePoints[1]+1;
3834 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3835 // with already applied percent bonus from Elemental Weapons talent
3836 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3837 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3838 switch(enchnting_damage)
3840 // Rank 1
3841 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3842 // Rank 2
3843 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3844 case 5: enchant_id = 3025; break; // 20%
3845 // Rank 3
3846 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3847 case 7: enchant_id = 3027; break; // 20%
3848 // Rank 4
3849 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3850 case 10: enchant_id = 503; break; // 14%
3851 case 11: enchant_id = 3031; break; // 20%
3852 // Rank 5
3853 case 15: enchant_id = 3035; break; // 0%
3854 case 16: enchant_id = 1663; break; // 7%
3855 case 17: enchant_id = 3033; break; // 14%
3856 case 18: enchant_id = 3034; break; // 20%
3857 // Rank 6
3858 case 28: enchant_id = 3038; break; // 0%
3859 case 29: enchant_id = 683; break; // 7%
3860 case 31: enchant_id = 3036; break; // 14%
3861 case 33: enchant_id = 3037; break; // 20%
3862 // Rank 7
3863 case 40: enchant_id = 3041; break; // 0%
3864 case 42: enchant_id = 1664; break; // 7%
3865 case 45: enchant_id = 3039; break; // 14%
3866 case 48: enchant_id = 3040; break; // 20%
3867 // Rank 8
3868 case 49: enchant_id = 3044; break; // 0%
3869 case 52: enchant_id = 2632; break; // 7%
3870 case 55: enchant_id = 3042; break; // 14%
3871 case 58: enchant_id = 3043; break; // 20%
3872 // Rank 9
3873 case 62: enchant_id = 2633; break; // 0%
3874 case 66: enchant_id = 3018; break; // 7%
3875 case 70: enchant_id = 3019; break; // 14%
3876 case 74: enchant_id = 3020; break; // 20%
3877 default:
3878 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3879 return;
3883 if (!enchant_id)
3885 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3886 return;
3889 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3890 if(!pEnchant)
3892 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3893 return;
3896 // select enchantment duration
3897 uint32 duration;
3899 // rogue family enchantments exception by duration
3900 if(m_spellInfo->Id==38615)
3901 duration = 1800; // 30 mins
3902 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3903 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3904 duration = 3600; // 1 hour
3905 // shaman family enchantments
3906 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3907 duration = 1800; // 30 mins
3908 // other cases with this SpellVisual already selected
3909 else if(m_spellInfo->SpellVisual[0]==215)
3910 duration = 1800; // 30 mins
3911 // some fishing pole bonuses
3912 else if(m_spellInfo->SpellVisual[0]==563)
3913 duration = 600; // 10 mins
3914 // shaman rockbiter enchantments
3915 else if(m_spellInfo->SpellVisual[0]==0)
3916 duration = 1800; // 30 mins
3917 else if(m_spellInfo->Id==29702)
3918 duration = 300; // 5 mins
3919 else if(m_spellInfo->Id==37360)
3920 duration = 300; // 5 mins
3921 // default case
3922 else
3923 duration = 3600; // 1 hour
3925 // item can be in trade slot and have owner diff. from caster
3926 Player* item_owner = itemTarget->GetOwner();
3927 if(!item_owner)
3928 return;
3930 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3932 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3933 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3934 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3935 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3938 // remove old enchanting before applying new if equipped
3939 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3941 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3943 // add new enchanting if equipped
3944 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3947 void Spell::EffectTameCreature(uint32 /*i*/)
3949 if(m_caster->GetPetGUID())
3950 return;
3952 if(!unitTarget)
3953 return;
3955 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3956 return;
3958 Creature* creatureTarget = (Creature*)unitTarget;
3960 if(creatureTarget->isPet())
3961 return;
3963 if(m_caster->getClass() != CLASS_HUNTER)
3964 return;
3966 // cast finish successfully
3967 //SendChannelUpdate(0);
3968 finish();
3970 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3972 // kill original creature
3973 creatureTarget->setDeathState(JUST_DIED);
3974 creatureTarget->RemoveCorpse();
3975 creatureTarget->SetHealth(0); // just for nice GM-mode view
3977 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
3979 // prepare visual effect for levelup
3980 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
3982 // add to world
3983 pet->GetMap()->Add((Creature*)pet);
3985 // visual effect for levelup
3986 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
3988 // caster have pet now
3989 m_caster->SetPet(pet);
3991 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3993 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3994 ((Player*)m_caster)->PetSpellInitialize();
3998 void Spell::EffectSummonPet(uint32 i)
4000 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4002 Pet *OldSummon = m_caster->GetPet();
4004 // if pet requested type already exist
4005 if( OldSummon )
4007 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4009 // pet in corpse state can't be summoned
4010 if( OldSummon->isDead() )
4011 return;
4013 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4014 OldSummon->SetMapId(m_caster->GetMapId());
4016 float px, py, pz;
4017 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4019 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4020 m_caster->GetMap()->Add((Creature*)OldSummon);
4022 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4024 ((Player*)m_caster)->PetSpellInitialize();
4026 return;
4029 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4030 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4031 else
4032 return;
4035 Pet* NewSummon = new Pet;
4037 // petentry==0 for hunter "call pet" (current pet summoned if any)
4038 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4040 if(NewSummon->getPetType()==SUMMON_PET)
4042 // Remove Demonic Sacrifice auras (known pet)
4043 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4044 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4046 if((*itr)->GetModifier()->m_miscvalue==2228)
4048 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4049 itr = auraClassScripts.begin();
4051 else
4052 ++itr;
4056 return;
4059 // not error in case fail hunter call pet
4060 if(!petentry)
4062 delete NewSummon;
4063 return;
4066 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4068 if(!cInfo)
4070 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4071 delete NewSummon;
4072 return;
4075 Map *map = m_caster->GetMap();
4076 uint32 pet_number = objmgr.GeneratePetNumber();
4077 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4079 delete NewSummon;
4080 return;
4083 float px, py, pz;
4084 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4086 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4088 if(!NewSummon->IsPositionValid())
4090 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4091 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4092 delete NewSummon;
4093 return;
4096 uint32 petlevel = m_caster->getLevel();
4097 NewSummon->setPetType(SUMMON_PET);
4099 uint32 faction = m_caster->getFaction();
4100 if(m_caster->GetTypeId() == TYPEID_UNIT)
4102 if ( ((Creature*)m_caster)->isTotem() )
4103 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4104 else
4105 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4108 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4109 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4110 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4111 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4112 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4113 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4114 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4115 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4116 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4117 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4119 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4120 // this enables pet details window (Shift+P)
4122 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4123 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4124 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4126 NewSummon->InitStatsForLevel(petlevel);
4127 NewSummon->InitPetCreateSpells();
4129 if(NewSummon->getPetType()==SUMMON_PET)
4131 // Remove Demonic Sacrifice auras (new pet)
4132 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4133 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4135 if((*itr)->GetModifier()->m_miscvalue==2228)
4137 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4138 itr = auraClassScripts.begin();
4140 else
4141 ++itr;
4144 // generate new name for summon pet
4145 std::string new_name=objmgr.GeneratePetName(petentry);
4146 if(!new_name.empty())
4147 NewSummon->SetName(new_name);
4149 else if(NewSummon->getPetType()==HUNTER_PET)
4150 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4152 NewSummon->AIM_Initialize();
4153 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4154 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4156 map->Add((Creature*)NewSummon);
4158 m_caster->SetPet(NewSummon);
4159 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4161 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4163 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4164 ((Player*)m_caster)->PetSpellInitialize();
4168 void Spell::EffectLearnPetSpell(uint32 i)
4170 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4171 return;
4173 Player *_player = (Player*)m_caster;
4175 Pet *pet = _player->GetPet();
4176 if(!pet)
4177 return;
4178 if(!pet->isAlive())
4179 return;
4181 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4182 if(!learn_spellproto)
4183 return;
4185 pet->learnSpell(learn_spellproto->Id);
4187 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4188 _player->PetSpellInitialize();
4191 void Spell::EffectTaunt(uint32 /*i*/)
4193 // this effect use before aura Taunt apply for prevent taunt already attacking target
4194 // for spell as marked "non effective at already attacking target"
4195 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4197 if(unitTarget->getVictim()==m_caster)
4199 SendCastResult(SPELL_FAILED_DONT_REPORT);
4200 return;
4204 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4205 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4206 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4209 void Spell::EffectWeaponDmg(uint32 i)
4211 if(!unitTarget)
4212 return;
4213 if(!unitTarget->isAlive())
4214 return;
4216 // multiple weapon dmg effect workaround
4217 // execute only the last weapon damage
4218 // and handle all effects at once
4219 for (int j = 0; j < 3; j++)
4221 switch(m_spellInfo->Effect[j])
4223 case SPELL_EFFECT_WEAPON_DAMAGE:
4224 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4225 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4226 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4227 if (j < i) // we must calculate only at last weapon effect
4228 return;
4229 break;
4233 // some spell specific modifiers
4234 bool customBonusDamagePercentMod = false;
4235 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4236 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4237 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4238 bool normalized = false;
4240 int32 spell_bonus = 0; // bonus specific for spell
4241 switch(m_spellInfo->SpellFamilyName)
4243 case SPELLFAMILY_WARRIOR:
4245 // Whirlwind, single only spell with 2 weapon white damage apply if have
4246 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4248 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4249 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4251 // Devastate bonus and sunder armor refresh
4252 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4254 customBonusDamagePercentMod = true;
4255 bonusDamagePercentMod = 0.0f; // only applied if auras found
4257 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4258 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4260 SpellEntry const *proto = (*itr)->GetSpellProto();
4261 if(proto->SpellVisual[0] == 406 && proto->SpellIconID == 565)
4263 int32 duration = GetSpellDuration(proto);
4264 (*itr)->SetAuraDuration(duration);
4265 (*itr)->SendAuraUpdate(false);
4266 bonusDamagePercentMod += 1.0f; // +100%
4270 break;
4272 case SPELLFAMILY_ROGUE:
4274 // Ambush
4275 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4277 customBonusDamagePercentMod = true;
4278 bonusDamagePercentMod = 2.5f; // 250%
4280 // Mutilate (for each hand)
4281 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4283 bool found = false;
4284 // fast check
4285 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4286 found = true;
4287 // full aura scan
4288 else
4290 Unit::AuraMap const& auras = unitTarget->GetAuras();
4291 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4293 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4295 found = true;
4296 break;
4301 if(found)
4302 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4304 break;
4306 case SPELLFAMILY_PALADIN:
4308 // Seal of Command - receive benefit from Spell Damage and Healing
4309 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4311 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4312 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4314 break;
4316 case SPELLFAMILY_SHAMAN:
4318 // Skyshatter Harness item set bonus
4319 // Stormstrike
4320 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4322 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4323 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4325 // Stormstrike AP Buff
4326 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4328 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4329 break;
4336 int32 fixed_bonus = 0;
4337 for (int j = 0; j < 3; j++)
4339 switch(m_spellInfo->Effect[j])
4341 case SPELL_EFFECT_WEAPON_DAMAGE:
4342 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4343 fixed_bonus += CalculateDamage(j,unitTarget);
4344 break;
4345 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4346 fixed_bonus += CalculateDamage(j,unitTarget);
4347 normalized = true;
4348 break;
4349 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4350 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4352 // applied only to prev.effects fixed damage
4353 if(customBonusDamagePercentMod)
4354 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4355 else
4356 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4357 break;
4358 default:
4359 break; // not weapon damage effect, just skip
4363 // non-weapon damage
4364 int32 bonus = spell_bonus + fixed_bonus;
4366 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4367 if(bonus)
4369 UnitMods unitMod;
4370 switch(m_attackType)
4372 default:
4373 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4374 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4375 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4378 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4379 bonus = int32(bonus*weapon_total_pct);
4382 // + weapon damage with applied weapon% dmg to base weapon damage in call
4383 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4385 // total damage
4386 bonus = int32(bonus*totalDamagePercentMod);
4388 // prevent negative damage
4389 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4391 // Add melee damage bonuses (also check for negative)
4392 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4393 m_damage+= eff_damage;
4395 // Hemorrhage
4396 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4398 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4399 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4402 // Mangle (Cat): CP
4403 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4405 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4406 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4409 // take ammo
4410 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4412 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4414 // wands don't have ammo
4415 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4416 return;
4418 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4420 if(pItem->GetMaxStackCount()==1)
4422 // decrease durability for non-stackable throw weapon
4423 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4425 else
4427 // decrease items amount for stackable throw weapon
4428 uint32 count = 1;
4429 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4432 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4433 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4437 void Spell::EffectThreat(uint32 /*i*/)
4439 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4440 return;
4442 if(!unitTarget->CanHaveThreatList())
4443 return;
4445 unitTarget->AddThreat(m_caster, float(damage));
4448 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4450 if(!unitTarget)
4451 return;
4452 if(!unitTarget->isAlive())
4453 return;
4455 uint32 heal = m_caster->GetMaxHealth();
4457 m_healing+=heal;
4460 void Spell::EffectInterruptCast(uint32 /*i*/)
4462 if(!unitTarget)
4463 return;
4464 if(!unitTarget->isAlive())
4465 return;
4467 // TODO: not all spells that used this effect apply cooldown at school spells
4468 // also exist case: apply cooldown to interrupted cast only and to all spells
4469 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4471 if (unitTarget->m_currentSpells[i])
4473 // check if we can interrupt spell
4474 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4476 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4477 unitTarget->InterruptSpell(i,false);
4483 void Spell::EffectSummonObjectWild(uint32 i)
4485 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4487 GameObject* pGameObj = new GameObject;
4489 WorldObject* target = focusObject;
4490 if( !target )
4491 target = m_caster;
4493 float x,y,z;
4494 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4496 x = m_targets.m_destX;
4497 y = m_targets.m_destY;
4498 z = m_targets.m_destZ;
4500 else
4501 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4503 Map *map = target->GetMap();
4505 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4506 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4508 delete pGameObj;
4509 return;
4512 int32 duration = GetSpellDuration(m_spellInfo);
4513 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4514 pGameObj->SetSpellId(m_spellInfo->Id);
4516 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4517 m_caster->AddGameObject(pGameObj);
4518 map->Add(pGameObj);
4520 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4522 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4524 Player *pl = (Player*)m_caster;
4525 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4526 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4528 uint32 team = ALLIANCE;
4530 if(pl->GetTeam() == team)
4531 team = HORDE;
4533 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4538 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4540 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4542 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4543 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4545 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4550 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4552 GameObject* linkedGO = new GameObject;
4553 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4554 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4556 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4557 linkedGO->SetSpellId(m_spellInfo->Id);
4559 m_caster->AddGameObject(linkedGO);
4560 map->Add(linkedGO);
4562 else
4564 delete linkedGO;
4565 linkedGO = NULL;
4566 return;
4571 void Spell::EffectScriptEffect(uint32 effIndex)
4573 // TODO: we must implement hunter pet summon at login there (spell 6962)
4575 // by spell id
4576 switch(m_spellInfo->Id)
4578 // PX-238 Winter Wondervolt TRAP
4579 case 26275:
4581 if( unitTarget->HasAura(26272,0)
4582 || unitTarget->HasAura(26157,0)
4583 || unitTarget->HasAura(26273,0)
4584 || unitTarget->HasAura(26274,0))
4585 return;
4587 uint32 iTmpSpellId;
4589 switch(urand(0,3))
4591 case 0:
4592 iTmpSpellId = 26272;
4593 break;
4594 case 1:
4595 iTmpSpellId = 26157;
4596 break;
4597 case 2:
4598 iTmpSpellId = 26273;
4599 break;
4600 case 3:
4601 iTmpSpellId = 26274;
4602 break;
4605 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4607 return;
4610 // Bending Shinbone
4611 case 8856:
4613 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4614 return;
4616 uint32 spell_id = 0;
4617 switch(urand(1,5))
4619 case 1: spell_id = 8854; break;
4620 default: spell_id = 8855; break;
4623 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4624 return;
4627 // Healthstone creating spells
4628 case 6201:
4629 case 6202:
4630 case 5699:
4631 case 11729:
4632 case 11730:
4633 case 27230:
4635 uint32 itemtype;
4636 uint32 rank = 0;
4637 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4638 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4640 if((*i)->GetId() == 18692)
4642 rank = 1;
4643 break;
4645 else if((*i)->GetId() == 18693)
4647 rank = 2;
4648 break;
4652 static uint32 const itypes[6][3] = {
4653 { 5512,19004,19005}, // Minor Healthstone
4654 { 5511,19006,19007}, // Lesser Healthstone
4655 { 5509,19008,19009}, // Healthstone
4656 { 5510,19010,19011}, // Greater Healthstone
4657 { 9421,19012,19013}, // Major Healthstone
4658 {22103,22104,22105} // Master Healthstone
4661 switch(m_spellInfo->Id)
4663 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4664 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4665 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4666 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4667 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4668 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4669 default:
4670 return;
4672 DoCreateItem( effIndex, itemtype );
4673 return;
4675 // Brittle Armor - need remove one 24575 Brittle Armor aura
4676 case 24590:
4677 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4678 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4679 return;
4680 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4681 case 26465:
4682 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4683 return;
4684 // Orb teleport spells
4685 case 25140:
4686 case 25143:
4687 case 25650:
4688 case 25652:
4689 case 29128:
4690 case 29129:
4691 case 35376:
4692 case 35727:
4694 if(!unitTarget)
4695 return;
4697 uint32 spellid;
4698 switch(m_spellInfo->Id)
4700 case 25140: spellid = 32571; break;
4701 case 25143: spellid = 32572; break;
4702 case 25650: spellid = 30140; break;
4703 case 25652: spellid = 30141; break;
4704 case 29128: spellid = 32568; break;
4705 case 29129: spellid = 32569; break;
4706 case 35376: spellid = 25649; break;
4707 case 35727: spellid = 35730; break;
4708 default:
4709 return;
4712 unitTarget->CastSpell(unitTarget,spellid,false);
4713 return;
4716 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4717 case 22539:
4718 case 22972:
4719 case 22975:
4720 case 22976:
4721 case 22977:
4722 case 22978:
4723 case 22979:
4724 case 22980:
4725 case 22981:
4726 case 22982:
4727 case 22983:
4728 case 22984:
4729 case 22985:
4731 if(!unitTarget || !unitTarget->isAlive())
4732 return;
4734 // Onyxia Scale Cloak
4735 if(unitTarget->GetDummyAura(22683))
4736 return;
4738 // Shadow Flame
4739 m_caster->CastSpell(unitTarget, 22682, true);
4740 return;
4742 break;
4744 // Summon Black Qiraji Battle Tank
4745 case 26656:
4747 if(!unitTarget)
4748 return;
4750 // Prevent stacking of mounts
4751 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4753 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4754 if (unitTarget->GetAreaId() == 3428)
4755 unitTarget->CastSpell(unitTarget, 25863, false);
4756 else
4757 unitTarget->CastSpell(unitTarget, 26655, false);
4758 break;
4760 // Piccolo of the Flaming Fire
4761 case 17512:
4763 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4764 return;
4765 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4766 break;
4769 // Dreaming Glory
4770 case 28698:
4772 if(!unitTarget)
4773 return;
4774 unitTarget->CastSpell(unitTarget, 28694, true);
4775 break;
4778 // Netherbloom
4779 case 28702:
4781 if(!unitTarget)
4782 return;
4783 // 25% chance of casting a random buff
4784 if(roll_chance_i(75))
4785 return;
4787 // triggered spells are 28703 to 28707
4788 // Note: some sources say, that there was the possibility of
4789 // receiving a debuff. However, this seems to be removed by a patch.
4790 const uint32 spellid = 28703;
4792 // don't overwrite an existing aura
4793 for(uint8 i=0; i<5; i++)
4794 if(unitTarget->HasAura(spellid+i, 0))
4795 return;
4796 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4797 break;
4800 // Nightmare Vine
4801 case 28720:
4803 if(!unitTarget)
4804 return;
4805 // 25% chance of casting Nightmare Pollen
4806 if(roll_chance_i(75))
4807 return;
4808 unitTarget->CastSpell(unitTarget, 28721, true);
4809 break;
4812 // Mirren's Drinking Hat
4813 case 29830:
4815 uint32 item = 0;
4816 switch ( urand(1,6) )
4818 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4819 case 4: case 5: item = 23585; break;// Stouthammer Lite
4820 case 6: item = 23586; break;// Aerie Peak Pale Ale
4822 if (item)
4823 DoCreateItem(effIndex,item);
4824 break;
4826 // Improved Sprint
4827 case 30918:
4829 // Removes snares and roots.
4830 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4831 Unit::AuraMap& Auras = unitTarget->GetAuras();
4832 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4834 next = iter;
4835 ++next;
4836 Aura *aur = iter->second;
4837 if (!aur->IsPositive()) //only remove negative spells
4839 // check for mechanic mask
4840 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4842 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4843 if(Auras.empty())
4844 break;
4845 else
4846 next = Auras.begin();
4850 break;
4852 case 41126: // Flame Crash
4854 if(!unitTarget)
4855 return;
4857 unitTarget->CastSpell(unitTarget, 41131, true);
4858 break;
4860 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4862 if(!unitTarget)
4863 return;
4865 unitTarget->CastSpell(unitTarget, 44870, true);
4866 break;
4869 // Goblin Weather Machine
4870 case 46203:
4872 if(!unitTarget)
4873 return;
4875 uint32 spellId;
4876 switch(rand()%4)
4878 case 0:
4879 spellId=46740;
4880 break;
4881 case 1:
4882 spellId=46739;
4883 break;
4884 case 2:
4885 spellId=46738;
4886 break;
4887 case 3:
4888 spellId=46736;
4889 break;
4891 unitTarget->CastSpell(unitTarget, spellId, true);
4892 break;
4894 //5,000 Gold
4895 case 46642:
4897 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4898 return;
4900 ((Player*)unitTarget)->ModifyMoney(50000000);
4902 break;
4904 case 51770:
4906 if(!unitTarget)
4907 return;
4909 unitTarget->CastSpell(unitTarget,51771,false);
4910 break;
4913 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER )
4915 switch(m_spellInfo->Id)
4917 // Chimera Shot
4918 case 53209:
4920 uint32 spellId = 0;
4921 int32 basePoint = 0;
4922 Unit::AuraMap& Auras = unitTarget->GetAuras();
4923 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
4925 Aura *aura = (*i).second;
4926 if (aura->GetCasterGUID() != m_caster->GetGUID())
4927 continue;
4928 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
4929 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
4930 if (!(familyFlag & 0x000000800000C000LL))
4931 continue;
4932 // Refresh aura duration
4933 aura->SetAuraDuration(aura->GetAuraMaxDuration());
4934 aura->SendAuraUpdate(false);
4936 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
4937 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
4939 spellId = 53353; // 53353 Chimera Shot - Serpent
4940 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
4942 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
4943 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
4945 spellId = 53358; // 53358 Chimera Shot - Viper
4946 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
4948 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
4949 if (familyFlag & 0x0000000000008000LL)
4950 spellId = 53359; // 53359 Chimera Shot - Scorpid
4951 // ?? nothing say in spell desc (possibly need addition check)
4952 //if (familyFlag & 0x0000010000000000LL || // dot
4953 // familyFlag & 0x0000100000000000LL) // stun
4955 // spellId = 53366; // 53366 Chimera Shot - Wyvern
4958 if (spellId)
4959 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
4960 return;
4962 default:
4963 break;
4966 else if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4968 switch(m_spellInfo->SpellFamilyFlags)
4970 // Judgement
4971 case 0x800000:
4973 if(!unitTarget || !unitTarget->isAlive())
4974 return;
4975 uint32 spellId2 = 0;
4977 // all seals have aura dummy
4978 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4979 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4981 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4983 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4984 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4985 continue;
4987 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4988 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4990 if(spellId2 <= 1)
4991 continue;
4993 // found, remove seal
4994 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4996 // Sanctified Judgement
4997 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4998 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
5000 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
5002 int32 chance = (*i)->GetModifier()->m_amount;
5003 if ( roll_chance_i(chance) )
5005 int32 mana = spellInfo->manaCost;
5006 if ( Player* modOwner = m_caster->GetSpellModOwner() )
5007 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
5008 mana = int32(mana* 0.8f);
5009 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
5011 break;
5015 break;
5018 m_caster->CastSpell(unitTarget,spellId2,true);
5019 return;
5024 // normal DB scripted effect
5025 if(!unitTarget)
5026 return;
5028 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5029 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5032 void Spell::EffectSanctuary(uint32 /*i*/)
5034 if(!unitTarget)
5035 return;
5036 //unitTarget->CombatStop();
5038 unitTarget->CombatStop();
5039 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5040 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5041 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5043 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5047 void Spell::EffectAddComboPoints(uint32 /*i*/)
5049 if(!unitTarget)
5050 return;
5052 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5053 return;
5055 if(damage <= 0)
5056 return;
5058 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5061 void Spell::EffectDuel(uint32 i)
5063 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5064 return;
5066 Player *caster = (Player*)m_caster;
5067 Player *target = (Player*)unitTarget;
5069 // caster or target already have requested duel
5070 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5071 return;
5073 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5074 // Don't have to check the target's map since you cannot challenge someone across maps
5075 uint32 mapid = caster->GetMapId();
5076 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5078 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5079 return;
5082 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5083 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5085 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5086 return;
5089 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5090 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5092 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5093 return;
5096 //CREATE DUEL FLAG OBJECT
5097 GameObject* pGameObj = new GameObject;
5099 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5101 Map *map = m_caster->GetMap();
5102 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
5103 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5104 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5105 m_caster->GetPositionZ(),
5106 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5108 delete pGameObj;
5109 return;
5112 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5113 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5114 int32 duration = GetSpellDuration(m_spellInfo);
5115 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5116 pGameObj->SetSpellId(m_spellInfo->Id);
5118 m_caster->AddGameObject(pGameObj);
5119 map->Add(pGameObj);
5120 //END
5122 // Send request
5123 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5124 data << pGameObj->GetGUID();
5125 data << caster->GetGUID();
5126 caster->GetSession()->SendPacket(&data);
5127 target->GetSession()->SendPacket(&data);
5129 // create duel-info
5130 DuelInfo *duel = new DuelInfo;
5131 duel->initiator = caster;
5132 duel->opponent = target;
5133 duel->startTime = 0;
5134 duel->startTimer = 0;
5135 caster->duel = duel;
5137 DuelInfo *duel2 = new DuelInfo;
5138 duel2->initiator = caster;
5139 duel2->opponent = caster;
5140 duel2->startTime = 0;
5141 duel2->startTimer = 0;
5142 target->duel = duel2;
5144 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5145 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5148 void Spell::EffectStuck(uint32 /*i*/)
5150 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5151 return;
5153 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5154 return;
5156 Player* pTarget = (Player*)unitTarget;
5158 sLog.outDebug("Spell Effect: Stuck");
5159 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());
5161 if(pTarget->isInFlight())
5162 return;
5164 // homebind location is loaded always
5165 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5167 // Stuck spell trigger Hearthstone cooldown
5168 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5169 if(!spellInfo)
5170 return;
5171 Spell spell(pTarget,spellInfo,true,0);
5172 spell.SendSpellCooldown();
5175 void Spell::EffectSummonPlayer(uint32 /*i*/)
5177 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5178 return;
5180 // Evil Twin (ignore player summon, but hide this for summoner)
5181 if(unitTarget->GetDummyAura(23445))
5182 return;
5184 float x,y,z;
5185 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5187 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5189 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5190 data << uint64(m_caster->GetGUID()); // summoner guid
5191 data << uint32(m_caster->GetZoneId()); // summoner zone
5192 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5193 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5196 static ScriptInfo generateActivateCommand()
5198 ScriptInfo si;
5199 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5200 return si;
5203 void Spell::EffectActivateObject(uint32 effect_idx)
5205 if(!gameObjTarget)
5206 return;
5208 static ScriptInfo activateCommand = generateActivateCommand();
5210 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5212 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5215 void Spell::EffectApplyGlyph(uint32 i)
5217 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5218 return;
5220 Player *player = (Player*)m_caster;
5222 // remove old glyph
5223 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5225 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5227 player->RemoveAurasDueToSpell(old_gp->SpellId);
5228 player->SetGlyph(m_glyphIndex, 0);
5232 // apply new one
5233 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5235 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5237 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5239 if(gp->TypeFlags != gs->TypeFlags)
5241 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5242 return; // glyph slot missmatch
5246 player->CastSpell(m_caster, gp->SpellId, true);
5247 player->SetGlyph(m_glyphIndex, glyph);
5252 void Spell::EffectSummonTotem(uint32 i)
5254 uint8 slot = 0;
5255 switch(m_spellInfo->EffectMiscValueB[i])
5257 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5258 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5259 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5260 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5261 // Battle standard case
5262 case SUMMON_TYPE_TOTEM: slot = 254; break;
5263 // jewelery statue case, like totem without slot
5264 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5265 default: return;
5268 if(slot < MAX_TOTEM)
5270 uint64 guid = m_caster->m_TotemSlot[slot];
5271 if(guid != 0)
5273 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5274 if(OldTotem && OldTotem->isTotem())
5275 ((Totem*)OldTotem)->UnSummon();
5279 uint32 team = 0;
5280 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5281 team = ((Player*)m_caster)->GetTeam();
5283 Totem* pTotem = new Totem;
5285 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5287 delete pTotem;
5288 return;
5291 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5293 float x,y,z;
5294 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5296 // totem must be at same Z in case swimming caster and etc.
5297 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5298 z = m_caster->GetPositionZ();
5300 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5302 if(slot < MAX_TOTEM)
5303 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5305 pTotem->SetOwner(m_caster->GetGUID());
5306 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5308 int32 duration=GetSpellDuration(m_spellInfo);
5309 if(Player* modOwner = m_caster->GetSpellModOwner())
5310 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5311 pTotem->SetDuration(duration);
5313 if (damage) // if not spell info, DB values used
5315 pTotem->SetMaxHealth(damage);
5316 pTotem->SetHealth(damage);
5319 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5321 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5322 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5324 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5325 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5327 pTotem->Summon(m_caster);
5329 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5331 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5332 data << uint8(slot);
5333 data << uint64(pTotem->GetGUID());
5334 data << uint32(duration);
5335 data << uint32(m_spellInfo->Id);
5336 ((Player*)m_caster)->SendDirectMessage(&data);
5340 void Spell::EffectEnchantHeldItem(uint32 i)
5342 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5343 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5344 return;
5346 Player* item_owner = (Player*)unitTarget;
5347 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5349 if(!item )
5350 return;
5352 // must be equipped
5353 if(!item ->IsEquipped())
5354 return;
5356 if (m_spellInfo->EffectMiscValue[i])
5358 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5359 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5360 if(!duration)
5361 duration = m_currentBasePoints[i]+1; //Base points after ..
5362 if(!duration)
5363 duration = 10; //10 seconds for enchants which don't have listed duration
5365 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5366 if(!pEnchant)
5367 return;
5369 // Always go to temp enchantment slot
5370 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5372 // Enchantment will not be applied if a different one already exists
5373 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5374 return;
5376 // Apply the temporary enchantment
5377 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5378 item_owner->ApplyEnchantment(item,slot,true);
5382 void Spell::EffectDisEnchant(uint32 /*i*/)
5384 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5385 return;
5387 Player* p_caster = (Player*)m_caster;
5388 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5389 return;
5391 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5393 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5395 // item will be removed at disenchanting end
5398 void Spell::EffectInebriate(uint32 /*i*/)
5400 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5401 return;
5403 Player *player = (Player*)unitTarget;
5404 uint16 currentDrunk = player->GetDrunkValue();
5405 uint16 drunkMod = damage * 256;
5406 if (currentDrunk + drunkMod > 0xFFFF)
5407 currentDrunk = 0xFFFF;
5408 else
5409 currentDrunk += drunkMod;
5410 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5413 void Spell::EffectFeedPet(uint32 i)
5415 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5416 return;
5418 Player *_player = (Player*)m_caster;
5420 if(!itemTarget)
5421 return;
5423 Pet *pet = _player->GetPet();
5424 if(!pet)
5425 return;
5427 if(!pet->isAlive())
5428 return;
5430 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5431 if(benefit <= 0)
5432 return;
5434 uint32 count = 1;
5435 _player->DestroyItemCount(itemTarget,count,true);
5436 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5438 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5441 void Spell::EffectDismissPet(uint32 /*i*/)
5443 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5444 return;
5446 Pet* pet = m_caster->GetPet();
5448 // not let dismiss dead pet
5449 if(!pet||!pet->isAlive())
5450 return;
5452 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5455 void Spell::EffectSummonObject(uint32 i)
5457 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5459 uint8 slot = 0;
5460 switch(m_spellInfo->Effect[i])
5462 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5463 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5464 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5465 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5466 default: return;
5469 uint64 guid = m_caster->m_ObjectSlot[slot];
5470 if(guid != 0)
5472 GameObject* obj = NULL;
5473 if( m_caster )
5474 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5476 if(obj) obj->Delete();
5477 m_caster->m_ObjectSlot[slot] = 0;
5480 GameObject* pGameObj = new GameObject;
5482 float rot2 = sin(m_caster->GetOrientation()/2);
5483 float rot3 = cos(m_caster->GetOrientation()/2);
5485 float x,y,z;
5486 // If dest location if present
5487 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5489 x = m_targets.m_destX;
5490 y = m_targets.m_destY;
5491 z = m_targets.m_destZ;
5493 // Summon in random point all other units if location present
5494 else
5495 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5497 Map *map = m_caster->GetMap();
5498 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5500 delete pGameObj;
5501 return;
5504 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5505 int32 duration = GetSpellDuration(m_spellInfo);
5506 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5507 pGameObj->SetSpellId(m_spellInfo->Id);
5508 m_caster->AddGameObject(pGameObj);
5510 map->Add(pGameObj);
5511 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5512 data << pGameObj->GetGUID();
5513 m_caster->SendMessageToSet(&data,true);
5515 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5518 void Spell::EffectResurrect(uint32 /*effIndex*/)
5520 if(!unitTarget)
5521 return;
5522 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5523 return;
5525 if(unitTarget->isAlive())
5526 return;
5527 if(!unitTarget->IsInWorld())
5528 return;
5530 switch (m_spellInfo->Id)
5532 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5533 case 8342:
5534 if (roll_chance_i(67))
5536 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5537 return;
5539 break;
5540 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5541 case 22999:
5542 if (roll_chance_i(50))
5544 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5545 return;
5547 break;
5548 default:
5549 break;
5552 Player* pTarget = ((Player*)unitTarget);
5554 if(pTarget->isRessurectRequested()) // already have one active request
5555 return;
5557 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5558 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5560 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5561 SendResurrectRequest(pTarget);
5564 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5566 if(!unitTarget || !unitTarget->isAlive())
5567 return;
5569 if( unitTarget->m_extraAttacks )
5570 return;
5572 unitTarget->m_extraAttacks = damage;
5575 void Spell::EffectParry(uint32 /*i*/)
5577 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5578 ((Player*)unitTarget)->SetCanParry(true);
5581 void Spell::EffectBlock(uint32 /*i*/)
5583 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5584 ((Player*)unitTarget)->SetCanBlock(true);
5587 void Spell::EffectMomentMove(uint32 i)
5589 if(unitTarget->isInFlight())
5590 return;
5592 if( m_spellInfo->rangeIndex== 1) //self range
5594 uint32 mapid = m_caster->GetMapId();
5595 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5597 // before caster
5598 float fx,fy,fz;
5599 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5600 float ox,oy,oz;
5601 unitTarget->GetPosition(ox,oy,oz);
5603 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5604 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5606 fx = fx2;
5607 fy = fy2;
5608 fz = fz2;
5609 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5612 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5613 ((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));
5614 else
5615 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5619 void Spell::EffectReputation(uint32 i)
5621 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5622 return;
5624 Player *_player = (Player*)unitTarget;
5626 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5628 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5630 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5632 if(!factionEntry)
5633 return;
5635 _player->ModifyFactionReputation(factionEntry,rep_change);
5638 void Spell::EffectQuestComplete(uint32 i)
5640 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5641 return;
5643 Player *_player = (Player*)m_caster;
5645 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5646 _player->AreaExploredOrEventHappens(quest_id);
5649 void Spell::EffectSelfResurrect(uint32 i)
5651 if(!unitTarget || unitTarget->isAlive())
5652 return;
5653 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5654 return;
5655 if(!unitTarget->IsInWorld())
5656 return;
5658 uint32 health = 0;
5659 uint32 mana = 0;
5661 // flat case
5662 if(damage < 0)
5664 health = uint32(-damage);
5665 mana = m_spellInfo->EffectMiscValue[i];
5667 // percent case
5668 else
5670 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5671 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5672 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5675 Player *plr = ((Player*)unitTarget);
5676 plr->ResurrectPlayer(0.0f);
5678 plr->SetHealth( health );
5679 plr->SetPower(POWER_MANA, mana );
5680 plr->SetPower(POWER_RAGE, 0 );
5681 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5683 plr->SpawnCorpseBones();
5685 plr->SaveToDB();
5688 void Spell::EffectSkinning(uint32 /*i*/)
5690 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5691 return;
5692 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5693 return;
5695 Creature* creature = (Creature*) unitTarget;
5696 int32 targetLevel = creature->getLevel();
5698 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5700 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5701 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5703 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5705 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5707 // Double chances for elites
5708 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5711 void Spell::EffectCharge(uint32 /*i*/)
5713 if(!unitTarget || !m_caster)
5714 return;
5716 float x, y, z;
5717 unitTarget->GetContactPoint(m_caster, x, y, z);
5718 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5719 ((Creature *)unitTarget)->StopMoving();
5721 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5722 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5724 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5725 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5727 // not all charge effects used in negative spells
5728 if ( !IsPositiveSpell(m_spellInfo->Id))
5729 m_caster->Attack(unitTarget,true);
5732 void Spell::EffectSummonCritter(uint32 i)
5734 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5735 return;
5736 Player* player = (Player*)m_caster;
5738 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5739 if(!pet_entry)
5740 return;
5742 Pet* old_critter = player->GetMiniPet();
5744 // for same pet just despawn
5745 if(old_critter && old_critter->GetEntry() == pet_entry)
5747 player->RemoveMiniPet();
5748 return;
5751 // despawn old pet before summon new
5752 if(old_critter)
5753 player->RemoveMiniPet();
5755 // summon new pet
5756 Pet* critter = new Pet(MINI_PET);
5758 Map *map = m_caster->GetMap();
5759 uint32 pet_number = objmgr.GeneratePetNumber();
5760 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5761 map, pet_entry, pet_number))
5763 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5764 delete critter;
5765 return;
5768 float x,y,z;
5769 // If dest location if present
5770 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5772 x = m_targets.m_destX;
5773 y = m_targets.m_destY;
5774 z = m_targets.m_destZ;
5776 // Summon if dest location not present near caster
5777 else
5778 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5780 critter->Relocate(x,y,z,m_caster->GetOrientation());
5782 if(!critter->IsPositionValid())
5784 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5785 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5786 delete critter;
5787 return;
5790 critter->SetOwnerGUID(m_caster->GetGUID());
5791 critter->SetCreatorGUID(m_caster->GetGUID());
5792 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5793 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5795 critter->AIM_Initialize();
5796 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5797 critter->SetMaxHealth(1);
5798 critter->SetHealth(1);
5799 critter->SetLevel(1);
5801 // set timer for unsummon
5802 int32 duration = GetSpellDuration(m_spellInfo);
5803 if(duration > 0)
5804 critter->SetDuration(duration);
5806 std::string name = player->GetName();
5807 name.append(petTypeSuffix[critter->getPetType()]);
5808 critter->SetName( name );
5809 player->SetMiniPet(critter);
5811 map->Add((Creature*)critter);
5814 void Spell::EffectKnockBack(uint32 i)
5816 if(!unitTarget || !m_caster)
5817 return;
5819 // Effect only works on players
5820 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5821 return;
5823 float vsin = sin(m_caster->GetAngle(unitTarget));
5824 float vcos = cos(m_caster->GetAngle(unitTarget));
5826 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5827 data.append(unitTarget->GetPackGUID());
5828 data << uint32(0); // Sequence
5829 data << float(vcos); // x direction
5830 data << float(vsin); // y direction
5831 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5832 data << float(damage/-10); // Z Movement speed (vertical)
5834 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5837 void Spell::EffectSendTaxi(uint32 i)
5839 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5840 return;
5842 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5843 if(!entry)
5844 return;
5846 std::vector<uint32> nodes;
5848 nodes.resize(2);
5849 nodes[0] = entry->from;
5850 nodes[1] = entry->to;
5852 uint32 mountid = 0;
5853 switch(m_spellInfo->Id)
5855 case 31606: //Stormcrow Amulet
5856 mountid = 17447;
5857 break;
5858 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5859 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5860 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5861 mountid = 22840;
5862 break;
5863 case 34905: //Stealth Flight
5864 mountid = 6851;
5865 break;
5866 case 53335: //Stormwind Harbor Flight - Peaceful
5867 mountid = 6852;
5868 break;
5871 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5875 void Spell::EffectPlayerPull(uint32 i)
5877 if(!unitTarget || !m_caster)
5878 return;
5880 // Effect only works on players
5881 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5882 return;
5884 float vsin = sin(unitTarget->GetAngle(m_caster));
5885 float vcos = cos(unitTarget->GetAngle(m_caster));
5887 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5888 data.append(unitTarget->GetPackGUID());
5889 data << uint32(0); // Sequence
5890 data << float(vcos); // x direction
5891 data << float(vsin); // y direction
5892 // Horizontal speed
5893 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5894 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5896 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5899 void Spell::EffectDispelMechanic(uint32 i)
5901 if(!unitTarget)
5902 return;
5904 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5906 Unit::AuraMap& Auras = unitTarget->GetAuras();
5907 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5909 next = iter;
5910 ++next;
5911 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5912 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5914 unitTarget->RemoveAurasDueToSpell(spell->Id);
5915 if(Auras.empty())
5916 break;
5917 else
5918 next = Auras.begin();
5921 return;
5924 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5926 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5927 return;
5928 Player *_player = (Player*)m_caster;
5929 Pet *pet = _player->GetPet();
5930 if(!pet)
5931 return;
5932 if(pet->isAlive())
5933 return;
5934 if(damage < 0)
5935 return;
5936 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5937 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5938 pet->setDeathState( ALIVE );
5939 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5940 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5942 pet->AIM_Initialize();
5944 _player->PetSpellInitialize();
5945 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5948 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5950 float mana = 0;
5951 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5953 if(!m_caster->m_TotemSlot[slot])
5954 continue;
5956 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5957 if(totem && totem->isTotem())
5959 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5960 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5961 if(spellInfo)
5962 mana += spellInfo->manaCost * damage / 100;
5963 ((Totem*)totem)->UnSummon();
5967 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5968 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5971 void Spell::EffectDurabilityDamage(uint32 i)
5973 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5974 return;
5976 int32 slot = m_spellInfo->EffectMiscValue[i];
5978 // FIXME: some spells effects have value -1/-2
5979 // Possibly its mean -1 all player equipped items and -2 all items
5980 if(slot < 0)
5982 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5983 return;
5986 // invalid slot value
5987 if(slot >= INVENTORY_SLOT_BAG_END)
5988 return;
5990 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5991 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5994 void Spell::EffectDurabilityDamagePCT(uint32 i)
5996 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5997 return;
5999 int32 slot = m_spellInfo->EffectMiscValue[i];
6001 // FIXME: some spells effects have value -1/-2
6002 // Possibly its mean -1 all player equipped items and -2 all items
6003 if(slot < 0)
6005 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6006 return;
6009 // invalid slot value
6010 if(slot >= INVENTORY_SLOT_BAG_END)
6011 return;
6013 if(damage <= 0)
6014 return;
6016 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6017 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6020 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6022 if(!unitTarget)
6023 return;
6025 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6028 void Spell::EffectTransmitted(uint32 effIndex)
6030 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6032 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6034 if (!goinfo)
6036 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6037 return;
6040 float fx,fy,fz;
6042 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6044 fx = m_targets.m_destX;
6045 fy = m_targets.m_destY;
6046 fz = m_targets.m_destZ;
6048 //FIXME: this can be better check for most objects but still hack
6049 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6051 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6052 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6054 else
6056 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6057 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6058 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6060 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6063 Map *cMap = m_caster->GetMap();
6065 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6067 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6068 { // but this is not proper, we really need to ignore not materialized objects
6069 SendCastResult(SPELL_FAILED_NOT_HERE);
6070 SendChannelUpdate(0);
6071 return;
6074 // replace by water level in this case
6075 fz = cMap->GetWaterLevel(fx,fy);
6077 // if gameobject is summoning object, it should be spawned right on caster's position
6078 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6080 m_caster->GetPosition(fx,fy,fz);
6083 GameObject* pGameObj = new GameObject;
6085 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6086 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6088 delete pGameObj;
6089 return;
6092 int32 duration = GetSpellDuration(m_spellInfo);
6094 switch(goinfo->type)
6096 case GAMEOBJECT_TYPE_FISHINGNODE:
6098 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6099 // Orientation3
6100 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6101 // Orientation4
6102 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6103 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6105 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6106 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6107 int32 lastSec;
6108 switch(urand(0, 3))
6110 case 0: lastSec = 3; break;
6111 case 1: lastSec = 7; break;
6112 case 2: lastSec = 13; break;
6113 case 3: lastSec = 17; break;
6116 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6117 break;
6119 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6121 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6123 pGameObj->AddUniqueUse((Player*)m_caster);
6124 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6126 break;
6128 case GAMEOBJECT_TYPE_FISHINGHOLE:
6129 case GAMEOBJECT_TYPE_CHEST:
6130 default:
6132 break;
6136 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6138 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6140 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6141 pGameObj->SetSpellId(m_spellInfo->Id);
6143 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6144 //m_caster->AddGameObject(pGameObj);
6145 //m_ObjToDel.push_back(pGameObj);
6147 cMap->Add(pGameObj);
6149 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6150 data << uint64(pGameObj->GetGUID());
6151 m_caster->SendMessageToSet(&data,true);
6153 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6155 GameObject* linkedGO = new GameObject;
6156 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6157 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6159 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6160 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6161 linkedGO->SetSpellId(m_spellInfo->Id);
6162 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6164 linkedGO->GetMap()->Add(linkedGO);
6166 else
6168 delete linkedGO;
6169 linkedGO = NULL;
6170 return;
6175 void Spell::EffectProspecting(uint32 /*i*/)
6177 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6178 return;
6180 Player* p_caster = (Player*)m_caster;
6181 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6182 return;
6184 if(itemTarget->GetCount() < 5)
6185 return;
6187 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6189 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6190 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6191 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6194 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6197 void Spell::EffectMilling(uint32 /*i*/)
6199 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6200 return;
6202 Player* p_caster = (Player*)m_caster;
6203 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6204 return;
6206 if(itemTarget->GetCount() < 5)
6207 return;
6209 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6211 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6212 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6213 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6216 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6219 void Spell::EffectSkill(uint32 /*i*/)
6221 sLog.outDebug("WORLD: SkillEFFECT");
6224 void Spell::EffectSummonDemon(uint32 i)
6226 float px = m_targets.m_destX;
6227 float py = m_targets.m_destY;
6228 float pz = m_targets.m_destZ;
6230 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6231 if (!Charmed)
6232 return;
6234 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6235 Charmed->SetLevel(m_caster->getLevel());
6237 // TODO: Add damage/mana/hp according to level
6239 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6241 // Enslave demon effect, without mana cost and cooldown
6242 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6244 // Inferno effect
6245 Charmed->CastSpell(Charmed, 22703, true, 0);
6249 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6250 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6251 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6252 This is why we use a half sec delay between the visual effect and the resurrection itself */
6253 void Spell::EffectSpiritHeal(uint32 /*i*/)
6256 if(!unitTarget || unitTarget->isAlive())
6257 return;
6258 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6259 return;
6260 if(!unitTarget->IsInWorld())
6261 return;
6263 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6264 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6265 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6266 ((Player*)unitTarget)->SpawnCorpseBones();
6270 // remove insignia spell effect
6271 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6273 sLog.outDebug("Effect: SkinPlayerCorpse");
6274 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6275 return;
6277 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6280 void Spell::EffectStealBeneficialBuff(uint32 i)
6282 sLog.outDebug("Effect: StealBeneficialBuff");
6284 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6285 return;
6287 std::vector <Aura *> steal_list;
6288 // Create dispel mask by dispel type
6289 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6290 Unit::AuraMap const& auras = unitTarget->GetAuras();
6291 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6293 Aura *aur = (*itr).second;
6294 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6296 // Need check for passive? this
6297 if (aur->IsPositive() && !aur->IsPassive())
6298 steal_list.push_back(aur);
6301 // Ok if exist some buffs for dispel try dispel it
6302 if (!steal_list.empty())
6304 std::list < std::pair<uint32,uint64> > success_list;
6305 int32 list_size = steal_list.size();
6306 // Dispell N = damage buffs (or while exist buffs for dispel)
6307 for (int32 count=0; count < damage && list_size > 0; ++count)
6309 // Random select buff for dispel
6310 Aura *aur = steal_list[urand(0, list_size-1)];
6311 // Not use chance for steal
6312 // TODO possible need do it
6313 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6315 // Remove buff from list for prevent doubles
6316 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6318 Aura *stealed = *j;
6319 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6321 j = steal_list.erase(j);
6322 --list_size;
6324 else
6325 ++j;
6328 // Really try steal and send log
6329 if (!success_list.empty())
6331 int32 count = success_list.size();
6332 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6333 data.append(unitTarget->GetPackGUID()); // Victim GUID
6334 data.append(m_caster->GetPackGUID()); // Caster GUID
6335 data << uint32(m_spellInfo->Id); // Dispell spell id
6336 data << uint8(0); // not used
6337 data << uint32(count); // count
6338 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6340 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6341 data << uint32(spellInfo->Id); // Spell Id
6342 data << uint8(0); // 0 - steals !=0 transfers
6343 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6345 m_caster->SendMessageToSet(&data, true);
6350 void Spell::EffectKillCredit(uint32 i)
6352 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6353 return;
6355 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6358 void Spell::EffectQuestFail(uint32 i)
6360 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6361 return;
6363 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6366 void Spell::EffectActivateRune(uint32 i)
6368 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6369 return;
6371 Player *plr = (Player*)m_caster;
6373 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6374 return;
6376 for(uint32 j = 0; j < MAX_RUNES; ++j)
6378 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[i])
6380 plr->SetRuneCooldown(j, 0);
6385 void Spell::EffectTitanGrip(uint32 i)
6387 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6388 ((Player*)unitTarget)->SetCanTitanGrip(true);