Fix debug message from last commit
[getmangos.git] / src / game / SpellEffects.cpp
blobe0abe79fcb2cbb29f8c0a6868da0d1bbfe13b2c5
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
1300 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1302 // In 303 exist spirit depend
1303 uint32 spirit = m_caster->GetStat(STAT_SPIRIT);
1304 switch (m_spellInfo->Id)
1306 case 1454: damage+=spirit; break;
1307 case 1455: damage+=spirit*15/10; break;
1308 case 1456: damage+=spirit*2; break;
1309 case 11687: damage+=spirit*25/10; break;
1310 case 11688:
1311 case 11689:
1312 case 27222:
1313 case 57946: damage+=spirit*3; break;
1314 default:
1315 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1316 return;
1318 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1319 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1320 if(int32(unitTarget->GetHealth()) > damage)
1322 // Shouldn't Appear in Combat Log
1323 unitTarget->ModifyHealth(-damage);
1325 int32 mana = damage;
1326 // Improved Life Tap mod
1327 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1328 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1330 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1331 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1333 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1335 // Mana Feed
1336 int32 manaFeedVal = 0;
1337 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1338 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1340 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1341 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1343 if(manaFeedVal > 0)
1345 manaFeedVal = manaFeedVal * mana / 100;
1346 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1349 else
1350 SendCastResult(SPELL_FAILED_FIZZLE);
1351 return;
1353 break;
1354 case SPELLFAMILY_PRIEST:
1355 switch(m_spellInfo->Id )
1357 case 28598: // Touch of Weakness triggered spell
1359 if(!unitTarget || !m_triggeredByAuraSpell)
1360 return;
1362 uint32 spellid = 0;
1363 switch(m_triggeredByAuraSpell->Id)
1365 case 2652: spellid = 2943; break; // Rank 1
1366 case 19261: spellid = 19249; break; // Rank 2
1367 case 19262: spellid = 19251; break; // Rank 3
1368 case 19264: spellid = 19252; break; // Rank 4
1369 case 19265: spellid = 19253; break; // Rank 5
1370 case 19266: spellid = 19254; break; // Rank 6
1371 case 25461: spellid = 25460; break; // Rank 7
1372 default:
1373 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1374 return;
1376 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1377 return;
1380 break;
1381 case SPELLFAMILY_DRUID:
1382 switch(m_spellInfo->Id )
1384 case 5420: // Tree of Life passive
1386 // Tree of Life area effect
1387 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1388 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1389 return;
1392 break;
1393 case SPELLFAMILY_ROGUE:
1394 switch(m_spellInfo->Id )
1396 case 31231: // Cheat Death
1398 m_caster->CastSpell(m_caster,45182,true);
1399 return;
1401 case 5938: // Shiv
1403 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1404 return;
1406 Player *pCaster = ((Player*)m_caster);
1408 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1409 if(!item)
1410 return;
1412 // all poison enchantments is temporary
1413 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1414 if(!enchant_id)
1415 return;
1417 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1418 if(!pEnchant)
1419 return;
1421 for (int s=0;s<3;s++)
1423 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1424 continue;
1426 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1427 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1428 continue;
1430 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1433 m_caster->CastSpell(unitTarget, 5940, true);
1434 return;
1437 break;
1438 case SPELLFAMILY_HUNTER:
1439 // Steady Shot
1440 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1442 if( !unitTarget || !unitTarget->isAlive())
1443 return;
1445 bool found = false;
1447 // check dazed affect
1448 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1449 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1451 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1453 found = true;
1454 break;
1458 if(found)
1459 m_damage+= damage;
1460 return;
1462 // Kill command
1463 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1465 if(m_caster->getClass()!=CLASS_HUNTER)
1466 return;
1468 // clear hunter crit aura state
1469 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1471 // additional damage from pet to pet target
1472 Pet* pet = m_caster->GetPet();
1473 if(!pet || !pet->getVictim())
1474 return;
1476 uint32 spell_id = 0;
1477 switch (m_spellInfo->Id)
1479 case 34026: spell_id = 34027; break; // rank 1
1480 default:
1481 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1482 return;
1485 pet->CastSpell(pet->getVictim(), spell_id, true);
1486 return;
1489 switch(m_spellInfo->Id)
1491 case 23989: //Readiness talent
1493 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1494 return;
1496 //immediately finishes the cooldown for hunter abilities
1497 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1498 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1500 uint32 classspell = itr->first;
1501 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1503 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1505 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1507 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1508 data << uint32(classspell);
1509 data << uint64(m_caster->GetGUID());
1510 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1513 return;
1515 case 37506: // Scatter Shot
1517 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1518 return;
1520 // break Auto Shot and autohit
1521 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1522 m_caster->AttackStop();
1523 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1524 return;
1527 break;
1528 case SPELLFAMILY_PALADIN:
1529 switch(m_spellInfo->SpellIconID)
1531 case 156: // Holy Shock
1533 if(!unitTarget)
1534 return;
1536 int hurt = 0;
1537 int heal = 0;
1539 switch(m_spellInfo->Id)
1541 case 20473: hurt = 25912; heal = 25914; break;
1542 case 20929: hurt = 25911; heal = 25913; break;
1543 case 20930: hurt = 25902; heal = 25903; break;
1544 case 27174: hurt = 27176; heal = 27175; break;
1545 case 33072: hurt = 33073; heal = 33074; break;
1546 default:
1547 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1548 return;
1551 if(m_caster->IsFriendlyTo(unitTarget))
1552 m_caster->CastSpell(unitTarget, heal, true, 0);
1553 else
1554 m_caster->CastSpell(unitTarget, hurt, true, 0);
1556 return;
1558 case 561: // Judgement of command
1560 if(!unitTarget)
1561 return;
1563 uint32 spell_id = m_currentBasePoints[i]+1;
1564 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1565 if(!spell_proto)
1566 return;
1568 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1570 // decreased damage (/2) for non-stunned target.
1571 SpellModifier *mod = new SpellModifier;
1572 mod->op = SPELLMOD_DAMAGE;
1573 mod->value = -50;
1574 mod->type = SPELLMOD_PCT;
1575 mod->spellId = m_spellInfo->Id;
1576 mod->mask = 0x0000020000000000LL;
1577 mod->mask2= 0LL;
1579 ((Player*)m_caster)->AddSpellMod(mod, true);
1580 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1581 // mod deleted
1582 ((Player*)m_caster)->AddSpellMod(mod, false);
1584 else
1585 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1587 return;
1591 switch(m_spellInfo->Id)
1593 case 31789: // Righteous Defense (step 1)
1595 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1597 // non-standard cast requirement check
1598 if (!unitTarget || unitTarget->getAttackers().empty())
1600 // clear cooldown at fail
1601 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1603 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1605 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1606 data << uint32(m_spellInfo->Id);
1607 data << uint64(m_caster->GetGUID());
1608 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1611 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1612 return;
1615 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1616 // Clear targets for eff 1
1617 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1618 ihit->effectMask &= ~(1<<1);
1620 // not empty (checked)
1621 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1623 // chance to be selected from list
1624 float chance = 100.0f/attackers.size();
1625 uint32 count=0;
1626 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1628 if(!roll_chance_f(chance))
1629 continue;
1630 ++count;
1631 AddUnitTarget((*aItr), 1);
1634 // now let next effect cast spell at each target.
1635 return;
1637 case 37877: // Blessing of Faith
1639 if(!unitTarget)
1640 return;
1642 uint32 spell_id = 0;
1643 switch(unitTarget->getClass())
1645 case CLASS_DRUID: spell_id = 37878; break;
1646 case CLASS_PALADIN: spell_id = 37879; break;
1647 case CLASS_PRIEST: spell_id = 37880; break;
1648 case CLASS_SHAMAN: spell_id = 37881; break;
1649 default: return; // ignore for not healing classes
1652 m_caster->CastSpell(m_caster,spell_id,true);
1653 return;
1656 break;
1657 case SPELLFAMILY_SHAMAN:
1658 //Shaman Rockbiter Weapon
1659 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1661 uint32 spell_id = 0;
1662 switch(m_spellInfo->Id)
1664 case 8017: spell_id = 36494; break; // Rank 1
1665 case 8018: spell_id = 36750; break; // Rank 2
1666 case 8019: spell_id = 36755; break; // Rank 3
1667 case 10399: spell_id = 36759; break; // Rank 4
1668 case 16314: spell_id = 36763; break; // Rank 5
1669 case 16315: spell_id = 36766; break; // Rank 6
1670 case 16316: spell_id = 36771; break; // Rank 7
1671 case 25479: spell_id = 36775; break; // Rank 8
1672 case 25485: spell_id = 36499; break; // Rank 9
1673 default:
1674 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1675 return;
1678 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1680 if(!spellInfo)
1682 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1683 return;
1686 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1687 return;
1689 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1691 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1693 if(item->IsFitToSpellRequirements(m_spellInfo))
1695 Spell *spell = new Spell(m_caster, spellInfo, true);
1697 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1698 // at calculation applied affect from Elemental Weapons talent
1699 // real enchantment damage-1
1700 spell->m_currentBasePoints[1] = damage-1;
1702 SpellCastTargets targets;
1703 targets.setItemTarget( item );
1704 spell->prepare(&targets);
1708 return;
1711 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1713 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1714 return;
1716 // Regenerate 6% of Total Mana Every 3 secs
1717 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1718 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1719 return;
1722 break;
1725 // pet auras
1726 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1728 m_caster->AddPetAura(petSpell);
1729 return;
1733 void Spell::EffectTriggerSpellWithValue(uint32 i)
1735 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1737 // normal case
1738 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1740 if(!spellInfo)
1742 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1743 return;
1746 int32 bp = damage;
1747 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1750 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1752 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1753 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1755 if(!spellInfo)
1757 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1758 return;
1761 finish();
1762 Spell *spell = new Spell(m_caster, spellInfo, true);
1764 SpellCastTargets targets;
1765 targets.setUnitTarget( unitTarget);
1766 spell->prepare(&targets);
1768 m_caster->SetCurrentCastedSpell(spell);
1769 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1773 void Spell::EffectForceCast(uint32 i)
1775 if( !unitTarget )
1776 return;
1778 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1780 // normal case
1781 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1783 if(!spellInfo)
1785 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1786 return;
1789 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1792 void Spell::EffectTriggerSpell(uint32 i)
1794 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1796 // special cases
1797 switch(triggered_spell_id)
1799 // Vanish
1800 case 18461:
1802 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1803 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1804 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1806 // if this spell is given to NPC it must handle rest by it's own AI
1807 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1808 return;
1810 // get highest rank of the Stealth spell
1811 uint32 spellId = 0;
1812 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1813 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1815 // only highest rank is shown in spell book, so simply check if shown in spell book
1816 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1817 continue;
1819 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1820 if (!spellInfo)
1821 continue;
1823 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1825 spellId = spellInfo->Id;
1826 break;
1830 // no Stealth spell found
1831 if (!spellId)
1832 return;
1834 // reset cooldown on it if needed
1835 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1836 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1838 m_caster->CastSpell(m_caster, spellId, true);
1839 return;
1841 // just skip
1842 case 23770: // Sayge's Dark Fortune of *
1843 // not exist, common cooldown can be implemented in scripts if need.
1844 return;
1845 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1846 case 29284:
1848 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1849 if (!spell)
1850 return;
1852 for (int i=0; i < spell->StackAmount; ++i)
1853 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1854 return;
1856 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1857 case 29286:
1859 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1860 if (!spell)
1861 return;
1863 for (int i=0; i < spell->StackAmount; ++i)
1864 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1865 return;
1867 // Righteous Defense
1868 case 31980:
1870 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1871 return;
1873 // Cloak of Shadows
1874 case 35729 :
1876 Unit::AuraMap& Auras = m_caster->GetAuras();
1877 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1879 // remove all harmful spells on you...
1880 if( // ignore positive and passive auras
1881 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1882 // ignore physical auras
1883 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1884 // ignore immunity persistent spells
1885 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1887 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1888 iter = Auras.begin();
1891 return;
1893 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1894 case 41967:
1896 if (Unit *pet = m_caster->GetPet())
1897 pet->CastSpell(pet, 28305, true);
1898 return;
1902 // normal case
1903 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1905 if(!spellInfo)
1907 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1908 return;
1911 // some triggered spells require specific equipment
1912 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1914 // main hand weapon required
1915 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1917 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1919 // skip spell if no weapon in slot or broken
1920 if(!item || item->IsBroken() )
1921 return;
1923 // skip spell if weapon not fit to triggered spell
1924 if(!item->IsFitToSpellRequirements(spellInfo))
1925 return;
1928 // offhand hand weapon required
1929 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1931 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1933 // skip spell if no weapon in slot or broken
1934 if(!item || item->IsBroken() )
1935 return;
1937 // skip spell if weapon not fit to triggered spell
1938 if(!item->IsFitToSpellRequirements(spellInfo))
1939 return;
1943 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1944 bool instant = false;
1945 for(uint32 j = i+1; j < 3; ++j)
1947 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1949 instant = true;
1950 break;
1954 if(instant)
1956 if (unitTarget)
1957 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1959 else
1960 m_TriggerSpells.push_back(spellInfo);
1963 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1965 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1967 // normal case
1968 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1970 if(!spellInfo)
1972 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1973 m_spellInfo->Id,effect_idx,triggered_spell_id);
1974 return;
1977 if (m_CastItem)
1978 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1980 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1982 SpellCastTargets targets;
1983 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1984 spell->m_CastItem = m_CastItem;
1985 spell->prepare(&targets, NULL);
1988 void Spell::EffectTeleportUnits(uint32 i)
1990 if(!unitTarget || unitTarget->isInFlight())
1991 return;
1993 switch (m_spellInfo->EffectImplicitTargetB[i])
1995 case TARGET_INNKEEPER_COORDINATES:
1997 // Only players can teleport to innkeeper
1998 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1999 return;
2001 ((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);
2002 return;
2004 case TARGET_TABLE_X_Y_Z_COORDINATES:
2006 // TODO: Only players can teleport?
2007 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2008 return;
2009 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2010 if(!st)
2012 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
2013 return;
2015 ((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);
2016 break;
2018 case TARGET_BEHIND_VICTIM:
2020 // Get selected target for player (or victim for units)
2021 Unit *pTarget = NULL;
2022 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2023 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2024 else
2025 pTarget = m_caster->getVictim();
2026 // No target present - return
2027 if (!pTarget)
2028 return;
2029 // Init dest coordinates
2030 uint32 mapid = m_caster->GetMapId();
2031 float x = m_targets.m_destX;
2032 float y = m_targets.m_destY;
2033 float z = m_targets.m_destZ;
2034 float orientation = pTarget->GetOrientation();
2035 // Teleport
2036 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2037 ((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));
2038 else
2040 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2041 WorldPacket data;
2042 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2043 unitTarget->SendMessageToSet(&data, false);
2045 return;
2047 default:
2049 // If not exist data for dest location - return
2050 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2052 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2053 return;
2055 // Init dest coordinates
2056 uint32 mapid = m_caster->GetMapId();
2057 float x = m_targets.m_destX;
2058 float y = m_targets.m_destY;
2059 float z = m_targets.m_destZ;
2060 float orientation = unitTarget->GetOrientation();
2061 // Teleport
2062 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2063 ((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));
2064 else
2066 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2067 WorldPacket data;
2068 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2069 unitTarget->SendMessageToSet(&data, false);
2071 return;
2075 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2076 switch ( m_spellInfo->Id )
2078 // Dimensional Ripper - Everlook
2079 case 23442:
2081 int32 r = irand(0, 119);
2082 if ( r >= 70 ) // 7/12 success
2084 if ( r < 100 ) // 4/12 evil twin
2085 m_caster->CastSpell(m_caster,23445,true);
2086 else // 1/12 fire
2087 m_caster->CastSpell(m_caster,23449,true);
2089 return;
2091 // Ultrasafe Transporter: Toshley's Station
2092 case 36941:
2094 if ( roll_chance_i(50) ) // 50% success
2096 int32 rand_eff = urand(1,7);
2097 switch ( rand_eff )
2099 case 1:
2100 // soul split - evil
2101 m_caster->CastSpell(m_caster,36900,true);
2102 break;
2103 case 2:
2104 // soul split - good
2105 m_caster->CastSpell(m_caster,36901,true);
2106 break;
2107 case 3:
2108 // Increase the size
2109 m_caster->CastSpell(m_caster,36895,true);
2110 break;
2111 case 4:
2112 // Decrease the size
2113 m_caster->CastSpell(m_caster,36893,true);
2114 break;
2115 case 5:
2116 // Transform
2118 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2119 m_caster->CastSpell(m_caster,36897,true);
2120 else
2121 m_caster->CastSpell(m_caster,36899,true);
2122 break;
2124 case 6:
2125 // chicken
2126 m_caster->CastSpell(m_caster,36940,true);
2127 break;
2128 case 7:
2129 // evil twin
2130 m_caster->CastSpell(m_caster,23445,true);
2131 break;
2134 return;
2136 // Dimensional Ripper - Area 52
2137 case 36890:
2139 if ( roll_chance_i(50) ) // 50% success
2141 int32 rand_eff = urand(1,4);
2142 switch ( rand_eff )
2144 case 1:
2145 // soul split - evil
2146 m_caster->CastSpell(m_caster,36900,true);
2147 break;
2148 case 2:
2149 // soul split - good
2150 m_caster->CastSpell(m_caster,36901,true);
2151 break;
2152 case 3:
2153 // Increase the size
2154 m_caster->CastSpell(m_caster,36895,true);
2155 break;
2156 case 4:
2157 // Transform
2159 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2160 m_caster->CastSpell(m_caster,36897,true);
2161 else
2162 m_caster->CastSpell(m_caster,36899,true);
2163 break;
2167 return;
2172 void Spell::EffectApplyAura(uint32 i)
2174 if(!unitTarget)
2175 return;
2177 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2178 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2179 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2180 return;
2182 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2183 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2184 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2185 return;
2187 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2188 if(!caster)
2189 return;
2191 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2193 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2195 // Now Reduce spell duration using data received at spell hit
2196 int32 duration = Aur->GetAuraMaxDuration();
2197 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2198 Aur->setDiminishGroup(m_diminishGroup);
2200 // if Aura removed and deleted, do not continue.
2201 if(duration== 0 && !(Aur->IsPermanent()))
2203 delete Aur;
2204 return;
2207 if(duration != Aur->GetAuraMaxDuration())
2209 Aur->SetAuraMaxDuration(duration);
2210 Aur->SetAuraDuration(duration);
2213 bool added = unitTarget->AddAura(Aur);
2215 // Aura not added and deleted in AddAura call;
2216 if (!added)
2217 return;
2219 // found crash at character loading, broken pointer to Aur...
2220 // Aur was deleted in AddAura()...
2221 if(!Aur)
2222 return;
2224 // TODO Make a way so it works for every related spell!
2225 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2227 uint32 spellId = 0;
2228 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2229 spellId = 6788; // Weakened Soul
2230 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2231 spellId = 25771; // Forbearance
2232 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2233 spellId = 41425; // Hypothermia
2234 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2235 spellId = 11196; // Recently Bandaged
2236 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2237 spellId = 23230; // Blood Fury - Healing Reduction
2239 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2240 if (AdditionalSpellInfo)
2242 // applied at target by target
2243 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2244 unitTarget->AddAura(AdditionalAura);
2245 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2249 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2250 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2251 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2254 void Spell::EffectUnlearnSpecialization( uint32 i )
2256 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2257 return;
2259 Player *_player = (Player*)unitTarget;
2260 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2262 _player->removeSpell(spellToUnlearn);
2264 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2267 void Spell::EffectPowerDrain(uint32 i)
2269 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2270 return;
2272 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2274 if(!unitTarget)
2275 return;
2276 if(!unitTarget->isAlive())
2277 return;
2278 if(unitTarget->getPowerType() != drain_power)
2279 return;
2280 if(damage < 0)
2281 return;
2283 uint32 curPower = unitTarget->GetPower(drain_power);
2285 //add spell damage bonus
2286 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2288 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2289 uint32 power = damage;
2290 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2291 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2293 int32 new_damage;
2294 if(curPower < power)
2295 new_damage = curPower;
2296 else
2297 new_damage = power;
2299 unitTarget->ModifyPower(drain_power,-new_damage);
2301 if(drain_power == POWER_MANA)
2303 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2304 if(manaMultiplier==0)
2305 manaMultiplier = 1;
2307 if(Player *modOwner = m_caster->GetSpellModOwner())
2308 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2310 int32 gain = int32(new_damage*manaMultiplier);
2312 m_caster->ModifyPower(POWER_MANA,gain);
2313 //send log
2314 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2318 void Spell::EffectSendEvent(uint32 EffectIndex)
2320 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2322 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2323 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2325 switch(m_spellInfo->Id)
2327 case 23333: // Pickup Horde Flag
2328 /*do not uncomment .
2329 if(bg->GetTypeID()==BATTLEGROUND_WS)
2330 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2331 sLog.outDebug("Send Event Horde Flag Picked Up");
2332 break;
2333 /* not used :
2334 case 23334: // Drop Horde Flag
2335 if(bg->GetTypeID()==BATTLEGROUND_WS)
2336 bg->EventPlayerDroppedFlag((Player*)m_caster);
2337 sLog.outDebug("Drop Horde Flag");
2338 break;
2340 case 23335: // Pickup Alliance Flag
2341 /*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
2342 if(bg->GetTypeID()==BATTLEGROUND_WS)
2343 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2344 sLog.outDebug("Send Event Alliance Flag Picked Up");
2345 break;
2346 /* not used :
2347 case 23336: // Drop Alliance Flag
2348 if(bg->GetTypeID()==BATTLEGROUND_WS)
2349 bg->EventPlayerDroppedFlag((Player*)m_caster);
2350 sLog.outDebug("Drop Alliance Flag");
2351 break;
2352 case 23385: // Alliance Flag Returns
2353 if(bg->GetTypeID()==BATTLEGROUND_WS)
2354 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2355 sLog.outDebug("Alliance Flag Returned");
2356 break;
2357 case 23386: // Horde Flag Returns
2358 if(bg->GetTypeID()==BATTLEGROUND_WS)
2359 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2360 sLog.outDebug("Horde Flag Returned");
2361 break;*/
2362 case 34976:
2364 if(bg->GetTypeID()==BATTLEGROUND_EY)
2365 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2367 break;
2368 default:
2369 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2370 break;
2374 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2375 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2378 void Spell::EffectPowerBurn(uint32 i)
2380 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2381 return;
2383 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2385 if(!unitTarget)
2386 return;
2387 if(!unitTarget->isAlive())
2388 return;
2389 if(unitTarget->getPowerType()!=powertype)
2390 return;
2391 if(damage < 0)
2392 return;
2394 int32 curPower = int32(unitTarget->GetPower(powertype));
2396 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2397 uint32 power = damage;
2398 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2399 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2401 int32 new_damage = (curPower < power) ? curPower : power;
2403 unitTarget->ModifyPower(powertype,-new_damage);
2404 float multiplier = m_spellInfo->EffectMultipleValue[i];
2406 if(Player *modOwner = m_caster->GetSpellModOwner())
2407 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2409 new_damage = int32(new_damage*multiplier);
2410 m_damage+=new_damage;
2413 void Spell::EffectHeal( uint32 /*i*/ )
2415 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2417 // Try to get original caster
2418 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2420 // Skip if m_originalCaster not available
2421 if (!caster)
2422 return;
2424 int32 addhealth = damage;
2426 // Vessel of the Naaru (Vial of the Sunwell trinket)
2427 if (m_spellInfo->Id == 45064)
2429 // Amount of heal - depends from stacked Holy Energy
2430 int damageAmount = 0;
2431 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2432 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2433 if((*i)->GetId() == 45062)
2434 damageAmount+=(*i)->GetModifier()->m_amount;
2435 if (damageAmount)
2436 m_caster->RemoveAurasDueToSpell(45062);
2438 addhealth += damageAmount;
2440 // Swiftmend - consumes Regrowth or Rejuvenation
2441 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2443 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2444 // find most short by duration
2445 Aura *targetAura = NULL;
2446 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2448 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2449 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2451 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2452 targetAura = *i;
2456 if(!targetAura)
2458 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2459 return;
2461 int idx = 0;
2462 while(idx < 3)
2464 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2465 break;
2466 idx++;
2469 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2470 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2471 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2473 addhealth += tickheal * tickcount;
2475 else
2476 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2478 m_healing+=addhealth;
2482 void Spell::EffectHealPct( uint32 /*i*/ )
2484 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2486 // Try to get original caster
2487 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2489 // Skip if m_originalCaster not available
2490 if (!caster)
2491 return;
2493 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2494 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2496 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2497 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2499 if(caster->GetTypeId()==TYPEID_PLAYER)
2500 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2501 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2505 void Spell::EffectHealMechanical( uint32 /*i*/ )
2507 // Mechanic creature type should be correctly checked by targetCreatureType field
2508 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2510 // Try to get original caster
2511 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2513 // Skip if m_originalCaster not available
2514 if (!caster)
2515 return;
2517 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2518 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2519 unitTarget->ModifyHealth( int32(damage) );
2523 void Spell::EffectHealthLeech(uint32 i)
2525 if(!unitTarget)
2526 return;
2527 if(!unitTarget->isAlive())
2528 return;
2530 if(damage < 0)
2531 return;
2533 sLog.outDebug("HealthLeech :%i", damage);
2535 float multiplier = m_spellInfo->EffectMultipleValue[i];
2537 if(Player *modOwner = m_caster->GetSpellModOwner())
2538 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2540 int32 new_damage = int32(damage*multiplier);
2541 uint32 curHealth = unitTarget->GetHealth();
2542 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2543 if(curHealth < new_damage)
2544 new_damage = curHealth;
2546 if(m_caster->isAlive())
2548 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2550 m_caster->ModifyHealth(new_damage);
2552 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2553 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2555 // m_healthLeech+=tmpvalue;
2556 // m_damage+=new_damage;
2559 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2561 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2562 return;
2564 Player* player = (Player*)unitTarget;
2566 uint32 newitemid = itemtype;
2567 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2568 if(!pProto)
2570 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2571 return;
2574 uint32 num_to_add;
2576 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2577 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2579 int32 basePoints = m_currentBasePoints[i];
2580 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2581 if (randomPoints)
2582 num_to_add = basePoints + irand(1, randomPoints);
2583 else
2584 num_to_add = basePoints + 1;
2586 else if (pProto->MaxCount == 1)
2587 num_to_add = 1;
2588 else if(player->getLevel() >= m_spellInfo->spellLevel)
2590 int32 basePoints = m_currentBasePoints[i];
2591 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2592 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2594 else
2595 num_to_add = 2;
2597 if (num_to_add < 1)
2598 num_to_add = 1;
2599 if (num_to_add > pProto->Stackable)
2600 num_to_add = pProto->Stackable;
2602 // init items_count to 1, since 1 item will be created regardless of specialization
2603 int items_count=1;
2604 // the chance to create additional items
2605 float additionalCreateChance=0.0f;
2606 // the maximum number of created additional items
2607 uint8 additionalMaxNum=0;
2608 // get the chance and maximum number for creating extra items
2609 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2611 // roll with this chance till we roll not to create or we create the max num
2612 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2613 ++items_count;
2616 // really will be created more items
2617 num_to_add *= items_count;
2619 // can the player store the new item?
2620 ItemPosCountVec dest;
2621 uint32 no_space = 0;
2622 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2623 if( msg != EQUIP_ERR_OK )
2625 // convert to possible store amount
2626 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2627 num_to_add -= no_space;
2628 else
2630 // if not created by another reason from full inventory or unique items amount limitation
2631 player->SendEquipError( msg, NULL, NULL );
2632 return;
2636 if(num_to_add)
2638 // create the new item and store it
2639 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2641 // was it successful? return error if not
2642 if(!pItem)
2644 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2645 return;
2648 // set the "Crafted by ..." property of the item
2649 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2650 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2652 // send info to the client
2653 if(pItem)
2654 player->SendNewItem(pItem, num_to_add, true, true);
2656 // we succeeded in creating at least one item, so a levelup is possible
2657 player->UpdateCraftSkill(m_spellInfo->Id);
2660 // for battleground marks send by mail if not add all expected
2661 if(no_space > 0 )
2663 BattleGroundTypeId bgType;
2664 switch(m_spellInfo->Id)
2666 case SPELL_AV_MARK_WINNER:
2667 case SPELL_AV_MARK_LOSER:
2668 bgType = BATTLEGROUND_AV;
2669 break;
2670 case SPELL_WS_MARK_WINNER:
2671 case SPELL_WS_MARK_LOSER:
2672 bgType = BATTLEGROUND_WS;
2673 break;
2674 case SPELL_AB_MARK_WINNER:
2675 case SPELL_AB_MARK_LOSER:
2676 bgType = BATTLEGROUND_AB;
2677 break;
2678 default:
2679 return;
2682 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2683 bg->SendRewardMarkByMail(player,newitemid,no_space);
2687 void Spell::EffectCreateItem(uint32 i)
2689 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2692 void Spell::EffectPersistentAA(uint32 i)
2694 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2696 if(Player* modOwner = m_caster->GetSpellModOwner())
2697 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2699 int32 duration = GetSpellDuration(m_spellInfo);
2700 DynamicObject* dynObj = new DynamicObject;
2701 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))
2703 delete dynObj;
2704 return;
2706 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2707 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2708 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2709 m_caster->AddDynObject(dynObj);
2710 dynObj->GetMap()->Add(dynObj);
2713 void Spell::EffectEnergize(uint32 i)
2715 if(!unitTarget)
2716 return;
2717 if(!unitTarget->isAlive())
2718 return;
2720 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2721 return;
2723 // Some level depends spells
2724 int multiplier = 0;
2725 int level_diff = 0;
2726 switch (m_spellInfo->Id)
2728 // Restore Energy
2729 case 9512:
2730 level_diff = m_caster->getLevel() - 40;
2731 multiplier = 2;
2732 break;
2733 // Blood Fury
2734 case 24571:
2735 level_diff = m_caster->getLevel() - 60;
2736 multiplier = 10;
2737 break;
2738 // Burst of Energy
2739 case 24532:
2740 level_diff = m_caster->getLevel() - 60;
2741 multiplier = 4;
2742 break;
2743 default:
2744 break;
2747 if (level_diff > 0)
2748 damage -= multiplier * level_diff;
2750 if(damage < 0)
2751 return;
2753 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2755 if(unitTarget->GetMaxPower(power) == 0)
2756 return;
2758 unitTarget->ModifyPower(power,damage);
2759 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2761 // Mad Alchemist's Potion
2762 if (m_spellInfo->Id == 45051)
2764 // find elixirs on target
2765 uint32 elixir_mask = 0;
2766 Unit::AuraMap& Auras = unitTarget->GetAuras();
2767 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2769 uint32 spell_id = itr->second->GetId();
2770 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2771 elixir_mask |= mask;
2774 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2775 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2777 // get all available elixirs by mask and spell level
2778 std::vector<uint32> elixirs;
2779 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2780 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2782 if (itr->second & elixir_mask)
2784 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2785 continue;
2787 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2788 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2789 continue;
2791 elixirs.push_back(itr->first);
2795 if (!elixirs.empty())
2797 // cast random elixir on target
2798 uint32 rand_spell = urand(0,elixirs.size()-1);
2799 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2804 void Spell::EffectEnergisePct(uint32 i)
2806 if(!unitTarget)
2807 return;
2808 if(!unitTarget->isAlive())
2809 return;
2811 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2812 return;
2814 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2816 uint32 maxPower = unitTarget->GetMaxPower(power);
2817 if(maxPower == 0)
2818 return;
2820 uint32 gain = damage * maxPower / 100;
2821 unitTarget->ModifyPower(power, gain);
2822 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2825 void Spell::SendLoot(uint64 guid, LootType loottype)
2827 Player* player = (Player*)m_caster;
2828 if (!player)
2829 return;
2831 if (gameObjTarget)
2833 if (Script->GOHello(player, gameObjTarget))
2834 return;
2836 switch (gameObjTarget->GetGoType())
2838 case GAMEOBJECT_TYPE_DOOR:
2839 case GAMEOBJECT_TYPE_BUTTON:
2840 gameObjTarget->UseDoorOrButton();
2841 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2842 return;
2844 case GAMEOBJECT_TYPE_QUESTGIVER:
2845 // start or end quest
2846 player->PrepareQuestMenu(guid);
2847 player->SendPreparedQuest(guid);
2848 return;
2850 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2851 // triggering linked GO
2852 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2853 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2854 return;
2856 case GAMEOBJECT_TYPE_GOOBER:
2857 // goober_scripts can be triggered if the player don't have the quest
2858 if (gameObjTarget->GetGOInfo()->goober.eventId)
2860 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2861 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2864 // cast goober spell
2865 if (gameObjTarget->GetGOInfo()->goober.questId)
2866 ///Quest require to be active for GO using
2867 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2868 return;
2870 gameObjTarget->AddUniqueUse(player);
2871 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2873 //TODO? Objective counting called without spell check but with quest objective check
2874 // if send spell id then this line will duplicate to spell casting call (double counting)
2875 // So we or have this line and not required in quest_template have reqSpellIdN
2876 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2877 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2879 // triggering linked GO
2880 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2881 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2883 return;
2885 case GAMEOBJECT_TYPE_CHEST:
2886 // TODO: possible must be moved to loot release (in different from linked triggering)
2887 if (gameObjTarget->GetGOInfo()->chest.eventId)
2889 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2890 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2893 // triggering linked GO
2894 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2895 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2897 // Don't return, let loots been taken
2901 // Send loot
2902 player->SendLoot(guid, loottype);
2905 void Spell::EffectOpenLock(uint32 /*i*/)
2907 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2909 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2910 return;
2913 Player* player = (Player*)m_caster;
2915 LootType loottype = LOOT_CORPSE;
2916 uint32 lockId = 0;
2917 uint64 guid = 0;
2919 // Get lockId
2920 if(gameObjTarget)
2922 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2923 // Arathi Basin banner opening !
2924 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2925 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2927 //isAllowUseBattleGroundObject() already called in CanCast()
2928 // in battleground check
2929 if(BattleGround *bg = player->GetBattleGround())
2931 // check if it's correct bg
2932 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2933 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2934 return;
2937 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2939 //isAllowUseBattleGroundObject() already called in CanCast()
2940 // in battleground check
2941 if(BattleGround *bg = player->GetBattleGround())
2943 if(bg->GetTypeID() == BATTLEGROUND_EY)
2944 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2945 return;
2948 lockId = gameObjTarget->GetLockId();
2949 guid = gameObjTarget->GetGUID();
2951 else if(itemTarget)
2953 lockId = itemTarget->GetProto()->LockID;
2954 guid = itemTarget->GetGUID();
2956 else
2958 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2959 return;
2962 if(!lockId) // possible case for GO and maybe for items.
2964 SendLoot(guid, loottype);
2965 return;
2968 // Get LockInfo
2969 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2971 if (!lockInfo)
2973 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2974 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2975 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2976 return;
2979 // check key
2980 for(int i = 0; i < 8; ++i)
2982 // Type==1 This means lockInfo->Index[i] is an item
2983 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2985 SendLoot(guid, loottype);
2986 return;
2990 uint32 SkillId = 0;
2991 // Check and skill-up skill
2992 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2993 SkillId = m_spellInfo->EffectMiscValue[1];
2994 // pickpocketing spells
2995 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2996 SkillId = SKILL_LOCKPICKING;
2998 // skill bonus provided by casting spell (mostly item spells)
2999 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
3001 uint32 reqSkillValue = lockInfo->Skill[0];
3003 if(lockInfo->Skill[1]) // required pick lock skill applying
3005 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
3007 SendCastResult(SPELL_FAILED_FIZZLE);
3008 return;
3011 reqSkillValue = lockInfo->Skill[1];
3013 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
3015 SendCastResult(SPELL_FAILED_BAD_TARGETS);
3016 return;
3019 if ( SkillId )
3021 loottype = LOOT_SKINNING;
3022 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
3024 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
3025 return;
3028 // update skill if really known
3029 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3030 if(SkillValue) // non only item base skill
3032 if(gameObjTarget)
3034 // Allow one skill-up until respawned
3035 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3036 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3037 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3039 else if(itemTarget)
3041 // Do one skill-up
3042 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3043 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3048 SendLoot(guid, loottype);
3051 void Spell::EffectSummonChangeItem(uint32 i)
3053 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3054 return;
3056 Player *player = (Player*)m_caster;
3058 // applied only to using item
3059 if(!m_CastItem)
3060 return;
3062 // ... only to item in own inventory/bank/equip_slot
3063 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3064 return;
3066 uint32 newitemid = m_spellInfo->EffectItemType[i];
3067 if(!newitemid)
3068 return;
3070 uint16 pos = m_CastItem->GetPos();
3072 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3073 if( !pNewItem )
3074 return;
3076 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3078 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3079 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3082 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3084 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3085 player->DurabilityLoss(pNewItem, loosePercent);
3088 if( player->IsInventoryPos( pos ) )
3090 ItemPosCountVec dest;
3091 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3092 if( msg == EQUIP_ERR_OK )
3094 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3096 // prevent crash at access and unexpected charges counting with item update queue corrupt
3097 if(m_CastItem==m_targets.getItemTarget())
3098 m_targets.setItemTarget(NULL);
3100 m_CastItem = NULL;
3102 player->StoreItem( dest, pNewItem, true);
3103 return;
3106 else if( player->IsBankPos ( pos ) )
3108 ItemPosCountVec dest;
3109 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3110 if( msg == EQUIP_ERR_OK )
3112 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3114 // prevent crash at access and unexpected charges counting with item update queue corrupt
3115 if(m_CastItem==m_targets.getItemTarget())
3116 m_targets.setItemTarget(NULL);
3118 m_CastItem = NULL;
3120 player->BankItem( dest, pNewItem, true);
3121 return;
3124 else if( player->IsEquipmentPos ( pos ) )
3126 uint16 dest;
3127 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3128 if( msg == EQUIP_ERR_OK )
3130 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3132 // prevent crash at access and unexpected charges counting with item update queue corrupt
3133 if(m_CastItem==m_targets.getItemTarget())
3134 m_targets.setItemTarget(NULL);
3136 m_CastItem = NULL;
3138 player->EquipItem( dest, pNewItem, true);
3139 player->AutoUnequipOffhandIfNeed();
3140 return;
3144 // fail
3145 delete pNewItem;
3148 void Spell::EffectOpenSecretSafe(uint32 i)
3150 EffectOpenLock(i); //no difference for now
3153 void Spell::EffectProficiency(uint32 /*i*/)
3155 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3156 return;
3157 Player *p_target = (Player*)unitTarget;
3159 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3160 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3162 p_target->AddWeaponProficiency(subClassMask);
3163 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3165 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3167 p_target->AddArmorProficiency(subClassMask);
3168 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3172 void Spell::EffectApplyAreaAura(uint32 i)
3174 if(!unitTarget)
3175 return;
3176 if(!unitTarget->isAlive())
3177 return;
3179 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3180 unitTarget->AddAura(Aur);
3183 void Spell::EffectSummonType(uint32 i)
3185 switch(m_spellInfo->EffectMiscValueB[i])
3187 case SUMMON_TYPE_GUARDIAN:
3188 case SUMMON_TYPE_POSESSED:
3189 case SUMMON_TYPE_POSESSED2:
3190 case SUMMON_TYPE_GUARDIAN2:
3191 EffectSummonGuardian(i);
3192 break;
3193 case SUMMON_TYPE_WILD:
3194 EffectSummonWild(i);
3195 break;
3196 case SUMMON_TYPE_DEMON:
3197 EffectSummonDemon(i);
3198 break;
3199 case SUMMON_TYPE_SUMMON:
3200 EffectSummon(i);
3201 break;
3202 case SUMMON_TYPE_CRITTER:
3203 case SUMMON_TYPE_CRITTER2:
3204 case SUMMON_TYPE_CRITTER3:
3205 EffectSummonCritter(i);
3206 break;
3207 case SUMMON_TYPE_TOTEM_SLOT1:
3208 case SUMMON_TYPE_TOTEM_SLOT2:
3209 case SUMMON_TYPE_TOTEM_SLOT3:
3210 case SUMMON_TYPE_TOTEM_SLOT4:
3211 case SUMMON_TYPE_TOTEM:
3212 EffectSummonTotem(i);
3213 break;
3214 case SUMMON_TYPE_UNKNOWN1:
3215 case SUMMON_TYPE_UNKNOWN2:
3216 case SUMMON_TYPE_UNKNOWN3:
3217 case SUMMON_TYPE_UNKNOWN4:
3218 case SUMMON_TYPE_UNKNOWN5:
3219 break;
3220 default:
3221 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3222 break;
3226 void Spell::EffectSummon(uint32 i)
3228 if(m_caster->GetPetGUID())
3229 return;
3231 if(!unitTarget)
3232 return;
3233 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3234 if(!pet_entry)
3235 return;
3236 uint32 level = m_caster->getLevel();
3237 Pet* spawnCreature = new Pet(SUMMON_PET);
3239 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3241 // set timer for unsummon
3242 int32 duration = GetSpellDuration(m_spellInfo);
3243 if(duration > 0)
3244 spawnCreature->SetDuration(duration);
3246 return;
3249 Map *map = m_caster->GetMap();
3250 uint32 pet_number = objmgr.GeneratePetNumber();
3251 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3253 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3254 delete spawnCreature;
3255 return;
3258 // Summon in dest location
3259 float x,y,z;
3260 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3262 x = m_targets.m_destX;
3263 y = m_targets.m_destY;
3264 z = m_targets.m_destZ;
3266 else
3267 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3269 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3271 if(!spawnCreature->IsPositionValid())
3273 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3274 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3275 delete spawnCreature;
3276 return;
3279 // set timer for unsummon
3280 int32 duration = GetSpellDuration(m_spellInfo);
3281 if(duration > 0)
3282 spawnCreature->SetDuration(duration);
3284 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3285 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3286 spawnCreature->setPowerType(POWER_MANA);
3287 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3288 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3289 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3290 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3291 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3292 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3293 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3294 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3295 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3297 spawnCreature->InitStatsForLevel(level);
3299 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3301 spawnCreature->AIM_Initialize();
3302 spawnCreature->InitPetCreateSpells();
3303 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3304 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3306 std::string name = m_caster->GetName();
3307 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3308 spawnCreature->SetName( name );
3310 map->Add((Creature*)spawnCreature);
3312 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3314 m_caster->SetPet(spawnCreature);
3315 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3316 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3317 ((Player*)m_caster)->PetSpellInitialize();
3321 void Spell::EffectLearnSpell(uint32 i)
3323 if(!unitTarget)
3324 return;
3326 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3328 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3329 EffectLearnPetSpell(i);
3331 return;
3334 Player *player = (Player*)unitTarget;
3336 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3337 player->learnSpell(spellToLearn);
3339 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3342 void Spell::EffectDispel(uint32 i)
3344 if(!unitTarget)
3345 return;
3347 // Fill possible dispell list
3348 std::vector <Aura *> dispel_list;
3350 // Create dispel mask by dispel type
3351 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3352 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3353 Unit::AuraMap const& auras = unitTarget->GetAuras();
3354 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3356 Aura *aur = (*itr).second;
3357 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3359 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3361 bool positive = true;
3362 if (!aur->IsPositive())
3363 positive = false;
3364 else
3365 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3367 // do not remove positive auras if friendly target
3368 // negative auras if non-friendly target
3369 if(positive == unitTarget->IsFriendlyTo(m_caster))
3370 continue;
3372 // Add aura to dispel list
3373 dispel_list.push_back(aur);
3376 // Ok if exist some buffs for dispel try dispel it
3377 if (!dispel_list.empty())
3379 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3380 std::list < uint32 > fail_list; // spell_id
3381 int32 list_size = dispel_list.size();
3382 // Dispell N = damage buffs (or while exist buffs for dispel)
3383 for (int32 count=0; count < damage && list_size > 0; ++count)
3385 // Random select buff for dispel
3386 Aura *aur = dispel_list[urand(0, list_size-1)];
3388 SpellEntry const* spellInfo = aur->GetSpellProto();
3389 // Base dispel chance
3390 // TODO: possible chance depend from spell level??
3391 int32 miss_chance = 0;
3392 // Apply dispel mod from aura caster
3393 if (Unit *caster = aur->GetCaster())
3395 if ( Player* modOwner = caster->GetSpellModOwner() )
3396 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3398 // Try dispel
3399 if (roll_chance_i(miss_chance))
3400 fail_list.push_back(aur->GetId());
3401 else
3402 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3403 // Remove buff from list for prevent doubles
3404 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3406 Aura *dispeled = *j;
3407 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3409 j = dispel_list.erase(j);
3410 --list_size;
3412 else
3413 ++j;
3416 // Send success log and really remove auras
3417 if (!success_list.empty())
3419 int32 count = success_list.size();
3420 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3421 data.append(unitTarget->GetPackGUID()); // Victim GUID
3422 data.append(m_caster->GetPackGUID()); // Caster GUID
3423 data << uint32(m_spellInfo->Id); // Dispell spell id
3424 data << uint8(0); // not used
3425 data << uint32(count); // count
3426 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3428 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3429 data << uint32(spellInfo->Id); // Spell Id
3430 data << uint8(0); // 0 - dispeled !=0 cleansed
3431 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3433 m_caster->SendMessageToSet(&data, true);
3435 // On succes dispel
3436 // Devour Magic
3437 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3439 uint32 heal_spell = 0;
3440 switch (m_spellInfo->Id)
3442 case 19505: heal_spell = 19658; break;
3443 case 19731: heal_spell = 19732; break;
3444 case 19734: heal_spell = 19733; break;
3445 case 19736: heal_spell = 19735; break;
3446 case 27276: heal_spell = 27278; break;
3447 case 27277: heal_spell = 27279; break;
3448 default:
3449 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3450 break;
3452 if (heal_spell)
3453 m_caster->CastSpell(m_caster, heal_spell, true);
3456 // Send fail log to client
3457 if (!fail_list.empty())
3459 // Failed to dispell
3460 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3461 data << uint64(m_caster->GetGUID()); // Caster GUID
3462 data << uint64(unitTarget->GetGUID()); // Victim GUID
3463 data << uint32(m_spellInfo->Id); // Dispell spell id
3464 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3465 data << uint32(*j); // Spell Id
3466 m_caster->SendMessageToSet(&data, true);
3471 void Spell::EffectDualWield(uint32 /*i*/)
3473 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3474 ((Player*)unitTarget)->SetCanDualWield(true);
3477 void Spell::EffectPull(uint32 /*i*/)
3479 // TODO: create a proper pull towards distract spell center for distract
3480 sLog.outDebug("WORLD: Spell Effect DUMMY");
3483 void Spell::EffectDistract(uint32 /*i*/)
3485 // Check for possible target
3486 if (!unitTarget || unitTarget->isInCombat())
3487 return;
3489 // target must be OK to do this
3490 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3491 return;
3493 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3495 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3497 // For players just turn them
3498 WorldPacket data;
3499 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3500 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3501 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3503 else
3505 // Set creature Distracted, Stop it, And turn it
3506 unitTarget->SetOrientation(angle);
3507 unitTarget->StopMoving();
3508 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3512 void Spell::EffectPickPocket(uint32 /*i*/)
3514 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3515 return;
3517 // victim must be creature and attackable
3518 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3519 return;
3521 // victim have to be alive and humanoid or undead
3522 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3524 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3526 if (chance > irand(0, 19))
3528 // Stealing successful
3529 //sLog.outDebug("Sending loot from pickpocket");
3530 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3532 else
3534 // Reveal action + get attack
3535 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3536 if (((Creature*)unitTarget)->AI())
3537 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3542 void Spell::EffectAddFarsight(uint32 i)
3544 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3545 int32 duration = GetSpellDuration(m_spellInfo);
3546 DynamicObject* dynObj = new DynamicObject;
3547 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))
3549 delete dynObj;
3550 return;
3552 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3553 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3554 m_caster->AddDynObject(dynObj);
3555 dynObj->GetMap()->Add(dynObj);
3556 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3557 ((Player*)m_caster)->SetFarSight(dynObj->GetGUID());
3560 void Spell::EffectSummonWild(uint32 i)
3562 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3563 if(!creature_entry)
3564 return;
3566 uint32 level = m_caster->getLevel();
3568 // level of creature summoned using engineering item based at engineering skill level
3569 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3571 ItemPrototype const *proto = m_CastItem->GetProto();
3572 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3574 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3575 if(skill202)
3577 level = skill202/5;
3582 // select center of summon position
3583 float center_x = m_targets.m_destX;
3584 float center_y = m_targets.m_destY;
3585 float center_z = m_targets.m_destZ;
3587 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3589 int32 amount = damage > 0 ? damage : 1;
3591 for(int32 count = 0; count < amount; ++count)
3593 float px, py, pz;
3594 // If dest location if present
3595 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3597 // Summon 1 unit in dest location
3598 if (count == 0)
3600 px = m_targets.m_destX;
3601 py = m_targets.m_destY;
3602 pz = m_targets.m_destZ;
3604 // Summon in random point all other units if location present
3605 else
3606 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3608 // Summon if dest location not present near caster
3609 else
3610 m_caster->GetClosePoint(px,py,pz,3.0f);
3612 int32 duration = GetSpellDuration(m_spellInfo);
3614 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3616 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3620 void Spell::EffectSummonGuardian(uint32 i)
3622 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3623 if(!pet_entry)
3624 return;
3626 // Jewelery statue case (totem like)
3627 if(m_spellInfo->SpellIconID==2056)
3629 EffectSummonTotem(i);
3630 return;
3633 // set timer for unsummon
3634 int32 duration = GetSpellDuration(m_spellInfo);
3636 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3637 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3638 // so this code hack in fact
3639 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3640 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3641 return; // find old guardian, ignore summon
3643 // in another case summon new
3644 uint32 level = m_caster->getLevel();
3646 // level of pet summoned using engineering item based at engineering skill level
3647 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3649 ItemPrototype const *proto = m_CastItem->GetProto();
3650 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3652 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3653 if(skill202)
3655 level = skill202/5;
3660 // select center of summon position
3661 float center_x = m_targets.m_destX;
3662 float center_y = m_targets.m_destY;
3663 float center_z = m_targets.m_destZ;
3665 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3667 int32 amount = damage > 0 ? damage : 1;
3669 for(int32 count = 0; count < amount; ++count)
3671 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3673 Map *map = m_caster->GetMap();
3674 uint32 pet_number = objmgr.GeneratePetNumber();
3675 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3677 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3678 delete spawnCreature;
3679 return;
3682 float px, py, pz;
3683 // If dest location if present
3684 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3686 // Summon 1 unit in dest location
3687 if (count == 0)
3689 px = m_targets.m_destX;
3690 py = m_targets.m_destY;
3691 pz = m_targets.m_destZ;
3693 // Summon in random point all other units if location present
3694 else
3695 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3697 // Summon if dest location not present near caster
3698 else
3699 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3701 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3703 if(!spawnCreature->IsPositionValid())
3705 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3706 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3707 delete spawnCreature;
3708 return;
3711 if(duration > 0)
3712 spawnCreature->SetDuration(duration);
3714 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3715 spawnCreature->setPowerType(POWER_MANA);
3716 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3717 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3718 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3719 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3720 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3721 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3722 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3724 spawnCreature->InitStatsForLevel(level);
3725 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3727 spawnCreature->AIM_Initialize();
3729 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3730 ((Player*)m_caster)->AddGuardian(spawnCreature);
3732 map->Add((Creature*)spawnCreature);
3736 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3738 if(!unitTarget)
3739 return;
3741 if(unitTarget->isInFlight())
3742 return;
3744 uint32 mapid = m_caster->GetMapId();
3745 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3747 float fx,fy,fz;
3748 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3750 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3751 ((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));
3752 else
3753 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3756 void Spell::EffectLearnSkill(uint32 i)
3758 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3759 return;
3761 if(damage < 0)
3762 return;
3764 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3765 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3766 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3769 void Spell::EffectAddHonor(uint32 /*i*/)
3771 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3772 return;
3774 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3776 // TODO: find formula for honor reward based on player's level!
3778 // now fixed only for level 70 players:
3779 if (((Player*)unitTarget)->getLevel() == 70)
3780 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3783 void Spell::EffectTradeSkill(uint32 /*i*/)
3785 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3786 return;
3787 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3788 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3789 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3792 void Spell::EffectEnchantItemPerm(uint32 i)
3794 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3795 return;
3796 if (!itemTarget)
3797 return;
3799 Player* p_caster = (Player*)m_caster;
3801 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3803 if (m_spellInfo->EffectMiscValue[i])
3805 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3807 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3808 if(!pEnchant)
3809 return;
3811 // item can be in trade slot and have owner diff. from caster
3812 Player* item_owner = itemTarget->GetOwner();
3813 if(!item_owner)
3814 return;
3816 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3818 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3819 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3820 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3821 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3824 // remove old enchanting before applying new if equipped
3825 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3827 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3829 // add new enchanting if equipped
3830 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3834 void Spell::EffectEnchantItemTmp(uint32 i)
3836 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3837 return;
3839 Player* p_caster = (Player*)m_caster;
3841 if(!itemTarget)
3842 return;
3844 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3846 // Shaman Rockbiter Weapon
3847 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3849 int32 enchnting_damage = m_currentBasePoints[1]+1;
3851 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3852 // with already applied percent bonus from Elemental Weapons talent
3853 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3854 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3855 switch(enchnting_damage)
3857 // Rank 1
3858 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3859 // Rank 2
3860 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3861 case 5: enchant_id = 3025; break; // 20%
3862 // Rank 3
3863 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3864 case 7: enchant_id = 3027; break; // 20%
3865 // Rank 4
3866 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3867 case 10: enchant_id = 503; break; // 14%
3868 case 11: enchant_id = 3031; break; // 20%
3869 // Rank 5
3870 case 15: enchant_id = 3035; break; // 0%
3871 case 16: enchant_id = 1663; break; // 7%
3872 case 17: enchant_id = 3033; break; // 14%
3873 case 18: enchant_id = 3034; break; // 20%
3874 // Rank 6
3875 case 28: enchant_id = 3038; break; // 0%
3876 case 29: enchant_id = 683; break; // 7%
3877 case 31: enchant_id = 3036; break; // 14%
3878 case 33: enchant_id = 3037; break; // 20%
3879 // Rank 7
3880 case 40: enchant_id = 3041; break; // 0%
3881 case 42: enchant_id = 1664; break; // 7%
3882 case 45: enchant_id = 3039; break; // 14%
3883 case 48: enchant_id = 3040; break; // 20%
3884 // Rank 8
3885 case 49: enchant_id = 3044; break; // 0%
3886 case 52: enchant_id = 2632; break; // 7%
3887 case 55: enchant_id = 3042; break; // 14%
3888 case 58: enchant_id = 3043; break; // 20%
3889 // Rank 9
3890 case 62: enchant_id = 2633; break; // 0%
3891 case 66: enchant_id = 3018; break; // 7%
3892 case 70: enchant_id = 3019; break; // 14%
3893 case 74: enchant_id = 3020; break; // 20%
3894 default:
3895 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3896 return;
3900 if (!enchant_id)
3902 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3903 return;
3906 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3907 if(!pEnchant)
3909 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3910 return;
3913 // select enchantment duration
3914 uint32 duration;
3916 // rogue family enchantments exception by duration
3917 if(m_spellInfo->Id==38615)
3918 duration = 1800; // 30 mins
3919 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3920 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3921 duration = 3600; // 1 hour
3922 // shaman family enchantments
3923 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3924 duration = 1800; // 30 mins
3925 // other cases with this SpellVisual already selected
3926 else if(m_spellInfo->SpellVisual[0]==215)
3927 duration = 1800; // 30 mins
3928 // some fishing pole bonuses
3929 else if(m_spellInfo->SpellVisual[0]==563)
3930 duration = 600; // 10 mins
3931 // shaman rockbiter enchantments
3932 else if(m_spellInfo->SpellVisual[0]==0)
3933 duration = 1800; // 30 mins
3934 else if(m_spellInfo->Id==29702)
3935 duration = 300; // 5 mins
3936 else if(m_spellInfo->Id==37360)
3937 duration = 300; // 5 mins
3938 // default case
3939 else
3940 duration = 3600; // 1 hour
3942 // item can be in trade slot and have owner diff. from caster
3943 Player* item_owner = itemTarget->GetOwner();
3944 if(!item_owner)
3945 return;
3947 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3949 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3950 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3951 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3952 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3955 // remove old enchanting before applying new if equipped
3956 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3958 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3960 // add new enchanting if equipped
3961 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3964 void Spell::EffectTameCreature(uint32 /*i*/)
3966 if(m_caster->GetPetGUID())
3967 return;
3969 if(!unitTarget)
3970 return;
3972 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3973 return;
3975 Creature* creatureTarget = (Creature*)unitTarget;
3977 if(creatureTarget->isPet())
3978 return;
3980 if(m_caster->getClass() != CLASS_HUNTER)
3981 return;
3983 // cast finish successfully
3984 //SendChannelUpdate(0);
3985 finish();
3987 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3989 // kill original creature
3990 creatureTarget->setDeathState(JUST_DIED);
3991 creatureTarget->RemoveCorpse();
3992 creatureTarget->SetHealth(0); // just for nice GM-mode view
3994 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
3996 // prepare visual effect for levelup
3997 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
3999 // add to world
4000 pet->GetMap()->Add((Creature*)pet);
4002 // visual effect for levelup
4003 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4005 // caster have pet now
4006 m_caster->SetPet(pet);
4008 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4010 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4011 ((Player*)m_caster)->PetSpellInitialize();
4015 void Spell::EffectSummonPet(uint32 i)
4017 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4019 Pet *OldSummon = m_caster->GetPet();
4021 // if pet requested type already exist
4022 if( OldSummon )
4024 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4026 // pet in corpse state can't be summoned
4027 if( OldSummon->isDead() )
4028 return;
4030 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4031 OldSummon->SetMapId(m_caster->GetMapId());
4033 float px, py, pz;
4034 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4036 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4037 m_caster->GetMap()->Add((Creature*)OldSummon);
4039 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4041 ((Player*)m_caster)->PetSpellInitialize();
4043 return;
4046 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4047 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4048 else
4049 return;
4052 Pet* NewSummon = new Pet;
4054 // petentry==0 for hunter "call pet" (current pet summoned if any)
4055 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4057 if(NewSummon->getPetType()==SUMMON_PET)
4059 // Remove Demonic Sacrifice auras (known pet)
4060 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4061 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4063 if((*itr)->GetModifier()->m_miscvalue==2228)
4065 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4066 itr = auraClassScripts.begin();
4068 else
4069 ++itr;
4073 return;
4076 // not error in case fail hunter call pet
4077 if(!petentry)
4079 delete NewSummon;
4080 return;
4083 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4085 if(!cInfo)
4087 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4088 delete NewSummon;
4089 return;
4092 Map *map = m_caster->GetMap();
4093 uint32 pet_number = objmgr.GeneratePetNumber();
4094 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4096 delete NewSummon;
4097 return;
4100 float px, py, pz;
4101 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4103 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4105 if(!NewSummon->IsPositionValid())
4107 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4108 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4109 delete NewSummon;
4110 return;
4113 uint32 petlevel = m_caster->getLevel();
4114 NewSummon->setPetType(SUMMON_PET);
4116 uint32 faction = m_caster->getFaction();
4117 if(m_caster->GetTypeId() == TYPEID_UNIT)
4119 if ( ((Creature*)m_caster)->isTotem() )
4120 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4121 else
4122 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4125 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4126 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4127 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4128 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4129 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4130 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4131 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4132 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4133 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4134 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4136 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4137 // this enables pet details window (Shift+P)
4139 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4140 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4141 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4143 NewSummon->InitStatsForLevel(petlevel);
4144 NewSummon->InitPetCreateSpells();
4146 if(NewSummon->getPetType()==SUMMON_PET)
4148 // Remove Demonic Sacrifice auras (new pet)
4149 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4150 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4152 if((*itr)->GetModifier()->m_miscvalue==2228)
4154 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4155 itr = auraClassScripts.begin();
4157 else
4158 ++itr;
4161 // generate new name for summon pet
4162 std::string new_name=objmgr.GeneratePetName(petentry);
4163 if(!new_name.empty())
4164 NewSummon->SetName(new_name);
4166 else if(NewSummon->getPetType()==HUNTER_PET)
4167 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4169 NewSummon->AIM_Initialize();
4170 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4171 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4173 map->Add((Creature*)NewSummon);
4175 m_caster->SetPet(NewSummon);
4176 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4178 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4180 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4181 ((Player*)m_caster)->PetSpellInitialize();
4185 void Spell::EffectLearnPetSpell(uint32 i)
4187 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4188 return;
4190 Player *_player = (Player*)m_caster;
4192 Pet *pet = _player->GetPet();
4193 if(!pet)
4194 return;
4195 if(!pet->isAlive())
4196 return;
4198 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4199 if(!learn_spellproto)
4200 return;
4202 pet->learnSpell(learn_spellproto->Id);
4204 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4205 _player->PetSpellInitialize();
4208 void Spell::EffectTaunt(uint32 /*i*/)
4210 // this effect use before aura Taunt apply for prevent taunt already attacking target
4211 // for spell as marked "non effective at already attacking target"
4212 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4214 if(unitTarget->getVictim()==m_caster)
4216 SendCastResult(SPELL_FAILED_DONT_REPORT);
4217 return;
4221 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4222 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4223 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4226 void Spell::EffectWeaponDmg(uint32 i)
4228 if(!unitTarget)
4229 return;
4230 if(!unitTarget->isAlive())
4231 return;
4233 // multiple weapon dmg effect workaround
4234 // execute only the last weapon damage
4235 // and handle all effects at once
4236 for (int j = 0; j < 3; j++)
4238 switch(m_spellInfo->Effect[j])
4240 case SPELL_EFFECT_WEAPON_DAMAGE:
4241 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4242 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4243 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4244 if (j < i) // we must calculate only at last weapon effect
4245 return;
4246 break;
4250 // some spell specific modifiers
4251 bool customBonusDamagePercentMod = false;
4252 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4253 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4254 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4255 bool normalized = false;
4257 int32 spell_bonus = 0; // bonus specific for spell
4258 switch(m_spellInfo->SpellFamilyName)
4260 case SPELLFAMILY_WARRIOR:
4262 // Whirlwind, single only spell with 2 weapon white damage apply if have
4263 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4265 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4266 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4268 // Devastate bonus and sunder armor refresh
4269 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4271 customBonusDamagePercentMod = true;
4272 bonusDamagePercentMod = 0.0f; // only applied if auras found
4274 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4275 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4277 SpellEntry const *proto = (*itr)->GetSpellProto();
4278 if(proto->SpellVisual[0] == 406 && proto->SpellIconID == 565)
4280 int32 duration = GetSpellDuration(proto);
4281 (*itr)->SetAuraDuration(duration);
4282 (*itr)->SendAuraUpdate(false);
4283 bonusDamagePercentMod += 1.0f; // +100%
4287 break;
4289 case SPELLFAMILY_ROGUE:
4291 // Ambush
4292 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4294 customBonusDamagePercentMod = true;
4295 bonusDamagePercentMod = 2.5f; // 250%
4297 // Mutilate (for each hand)
4298 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4300 bool found = false;
4301 // fast check
4302 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4303 found = true;
4304 // full aura scan
4305 else
4307 Unit::AuraMap const& auras = unitTarget->GetAuras();
4308 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4310 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4312 found = true;
4313 break;
4318 if(found)
4319 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4321 break;
4323 case SPELLFAMILY_PALADIN:
4325 // Seal of Command - receive benefit from Spell Damage and Healing
4326 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4328 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4329 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4331 break;
4333 case SPELLFAMILY_SHAMAN:
4335 // Skyshatter Harness item set bonus
4336 // Stormstrike
4337 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4339 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4340 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4342 // Stormstrike AP Buff
4343 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4345 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4346 break;
4353 int32 fixed_bonus = 0;
4354 for (int j = 0; j < 3; j++)
4356 switch(m_spellInfo->Effect[j])
4358 case SPELL_EFFECT_WEAPON_DAMAGE:
4359 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4360 fixed_bonus += CalculateDamage(j,unitTarget);
4361 break;
4362 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4363 fixed_bonus += CalculateDamage(j,unitTarget);
4364 normalized = true;
4365 break;
4366 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4367 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4369 // applied only to prev.effects fixed damage
4370 if(customBonusDamagePercentMod)
4371 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4372 else
4373 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4374 break;
4375 default:
4376 break; // not weapon damage effect, just skip
4380 // non-weapon damage
4381 int32 bonus = spell_bonus + fixed_bonus;
4383 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4384 if(bonus)
4386 UnitMods unitMod;
4387 switch(m_attackType)
4389 default:
4390 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4391 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4392 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4395 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4396 bonus = int32(bonus*weapon_total_pct);
4399 // + weapon damage with applied weapon% dmg to base weapon damage in call
4400 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4402 // total damage
4403 bonus = int32(bonus*totalDamagePercentMod);
4405 // prevent negative damage
4406 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4408 // Add melee damage bonuses (also check for negative)
4409 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4410 m_damage+= eff_damage;
4412 // Hemorrhage
4413 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4415 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4416 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4419 // Mangle (Cat): CP
4420 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4422 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4423 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4426 // take ammo
4427 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4429 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4431 // wands don't have ammo
4432 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4433 return;
4435 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4437 if(pItem->GetMaxStackCount()==1)
4439 // decrease durability for non-stackable throw weapon
4440 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4442 else
4444 // decrease items amount for stackable throw weapon
4445 uint32 count = 1;
4446 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4449 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4450 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4454 void Spell::EffectThreat(uint32 /*i*/)
4456 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4457 return;
4459 if(!unitTarget->CanHaveThreatList())
4460 return;
4462 unitTarget->AddThreat(m_caster, float(damage));
4465 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4467 if(!unitTarget)
4468 return;
4469 if(!unitTarget->isAlive())
4470 return;
4472 uint32 heal = m_caster->GetMaxHealth();
4474 m_healing+=heal;
4477 void Spell::EffectInterruptCast(uint32 /*i*/)
4479 if(!unitTarget)
4480 return;
4481 if(!unitTarget->isAlive())
4482 return;
4484 // TODO: not all spells that used this effect apply cooldown at school spells
4485 // also exist case: apply cooldown to interrupted cast only and to all spells
4486 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4488 if (unitTarget->m_currentSpells[i])
4490 // check if we can interrupt spell
4491 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4493 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4494 unitTarget->InterruptSpell(i,false);
4500 void Spell::EffectSummonObjectWild(uint32 i)
4502 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4504 GameObject* pGameObj = new GameObject;
4506 WorldObject* target = focusObject;
4507 if( !target )
4508 target = m_caster;
4510 float x,y,z;
4511 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4513 x = m_targets.m_destX;
4514 y = m_targets.m_destY;
4515 z = m_targets.m_destZ;
4517 else
4518 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4520 Map *map = target->GetMap();
4522 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4523 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4525 delete pGameObj;
4526 return;
4529 int32 duration = GetSpellDuration(m_spellInfo);
4530 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4531 pGameObj->SetSpellId(m_spellInfo->Id);
4533 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4534 m_caster->AddGameObject(pGameObj);
4535 map->Add(pGameObj);
4537 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4539 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4541 Player *pl = (Player*)m_caster;
4542 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4543 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4545 uint32 team = ALLIANCE;
4547 if(pl->GetTeam() == team)
4548 team = HORDE;
4550 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4555 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4557 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4559 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4560 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4562 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4567 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4569 GameObject* linkedGO = new GameObject;
4570 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4571 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4573 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4574 linkedGO->SetSpellId(m_spellInfo->Id);
4576 m_caster->AddGameObject(linkedGO);
4577 map->Add(linkedGO);
4579 else
4581 delete linkedGO;
4582 linkedGO = NULL;
4583 return;
4588 void Spell::EffectScriptEffect(uint32 effIndex)
4590 // TODO: we must implement hunter pet summon at login there (spell 6962)
4592 // by spell id
4593 switch(m_spellInfo->Id)
4595 // PX-238 Winter Wondervolt TRAP
4596 case 26275:
4598 if( unitTarget->HasAura(26272,0)
4599 || unitTarget->HasAura(26157,0)
4600 || unitTarget->HasAura(26273,0)
4601 || unitTarget->HasAura(26274,0))
4602 return;
4604 uint32 iTmpSpellId;
4606 switch(urand(0,3))
4608 case 0:
4609 iTmpSpellId = 26272;
4610 break;
4611 case 1:
4612 iTmpSpellId = 26157;
4613 break;
4614 case 2:
4615 iTmpSpellId = 26273;
4616 break;
4617 case 3:
4618 iTmpSpellId = 26274;
4619 break;
4622 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4624 return;
4627 // Bending Shinbone
4628 case 8856:
4630 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4631 return;
4633 uint32 spell_id = 0;
4634 switch(urand(1,5))
4636 case 1: spell_id = 8854; break;
4637 default: spell_id = 8855; break;
4640 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4641 return;
4644 // Healthstone creating spells
4645 case 6201:
4646 case 6202:
4647 case 5699:
4648 case 11729:
4649 case 11730:
4650 case 27230:
4652 uint32 itemtype;
4653 uint32 rank = 0;
4654 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4655 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4657 if((*i)->GetId() == 18692)
4659 rank = 1;
4660 break;
4662 else if((*i)->GetId() == 18693)
4664 rank = 2;
4665 break;
4669 static uint32 const itypes[6][3] = {
4670 { 5512,19004,19005}, // Minor Healthstone
4671 { 5511,19006,19007}, // Lesser Healthstone
4672 { 5509,19008,19009}, // Healthstone
4673 { 5510,19010,19011}, // Greater Healthstone
4674 { 9421,19012,19013}, // Major Healthstone
4675 {22103,22104,22105} // Master Healthstone
4678 switch(m_spellInfo->Id)
4680 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4681 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4682 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4683 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4684 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4685 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4686 default:
4687 return;
4689 DoCreateItem( effIndex, itemtype );
4690 return;
4692 // Brittle Armor - need remove one 24575 Brittle Armor aura
4693 case 24590:
4694 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4695 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4696 return;
4697 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4698 case 26465:
4699 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4700 return;
4701 // Orb teleport spells
4702 case 25140:
4703 case 25143:
4704 case 25650:
4705 case 25652:
4706 case 29128:
4707 case 29129:
4708 case 35376:
4709 case 35727:
4711 if(!unitTarget)
4712 return;
4714 uint32 spellid;
4715 switch(m_spellInfo->Id)
4717 case 25140: spellid = 32571; break;
4718 case 25143: spellid = 32572; break;
4719 case 25650: spellid = 30140; break;
4720 case 25652: spellid = 30141; break;
4721 case 29128: spellid = 32568; break;
4722 case 29129: spellid = 32569; break;
4723 case 35376: spellid = 25649; break;
4724 case 35727: spellid = 35730; break;
4725 default:
4726 return;
4729 unitTarget->CastSpell(unitTarget,spellid,false);
4730 return;
4733 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4734 case 22539:
4735 case 22972:
4736 case 22975:
4737 case 22976:
4738 case 22977:
4739 case 22978:
4740 case 22979:
4741 case 22980:
4742 case 22981:
4743 case 22982:
4744 case 22983:
4745 case 22984:
4746 case 22985:
4748 if(!unitTarget || !unitTarget->isAlive())
4749 return;
4751 // Onyxia Scale Cloak
4752 if(unitTarget->GetDummyAura(22683))
4753 return;
4755 // Shadow Flame
4756 m_caster->CastSpell(unitTarget, 22682, true);
4757 return;
4759 break;
4761 // Summon Black Qiraji Battle Tank
4762 case 26656:
4764 if(!unitTarget)
4765 return;
4767 // Prevent stacking of mounts
4768 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4770 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4771 if (unitTarget->GetAreaId() == 3428)
4772 unitTarget->CastSpell(unitTarget, 25863, false);
4773 else
4774 unitTarget->CastSpell(unitTarget, 26655, false);
4775 break;
4777 // Piccolo of the Flaming Fire
4778 case 17512:
4780 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4781 return;
4782 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4783 break;
4786 // Dreaming Glory
4787 case 28698:
4789 if(!unitTarget)
4790 return;
4791 unitTarget->CastSpell(unitTarget, 28694, true);
4792 break;
4795 // Netherbloom
4796 case 28702:
4798 if(!unitTarget)
4799 return;
4800 // 25% chance of casting a random buff
4801 if(roll_chance_i(75))
4802 return;
4804 // triggered spells are 28703 to 28707
4805 // Note: some sources say, that there was the possibility of
4806 // receiving a debuff. However, this seems to be removed by a patch.
4807 const uint32 spellid = 28703;
4809 // don't overwrite an existing aura
4810 for(uint8 i=0; i<5; i++)
4811 if(unitTarget->HasAura(spellid+i, 0))
4812 return;
4813 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4814 break;
4817 // Nightmare Vine
4818 case 28720:
4820 if(!unitTarget)
4821 return;
4822 // 25% chance of casting Nightmare Pollen
4823 if(roll_chance_i(75))
4824 return;
4825 unitTarget->CastSpell(unitTarget, 28721, true);
4826 break;
4829 // Mirren's Drinking Hat
4830 case 29830:
4832 uint32 item = 0;
4833 switch ( urand(1,6) )
4835 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4836 case 4: case 5: item = 23585; break;// Stouthammer Lite
4837 case 6: item = 23586; break;// Aerie Peak Pale Ale
4839 if (item)
4840 DoCreateItem(effIndex,item);
4841 break;
4843 // Improved Sprint
4844 case 30918:
4846 // Removes snares and roots.
4847 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4848 Unit::AuraMap& Auras = unitTarget->GetAuras();
4849 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4851 next = iter;
4852 ++next;
4853 Aura *aur = iter->second;
4854 if (!aur->IsPositive()) //only remove negative spells
4856 // check for mechanic mask
4857 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4859 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4860 if(Auras.empty())
4861 break;
4862 else
4863 next = Auras.begin();
4867 break;
4869 case 41126: // Flame Crash
4871 if(!unitTarget)
4872 return;
4874 unitTarget->CastSpell(unitTarget, 41131, true);
4875 break;
4877 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4879 if(!unitTarget)
4880 return;
4882 unitTarget->CastSpell(unitTarget, 44870, true);
4883 break;
4886 // Goblin Weather Machine
4887 case 46203:
4889 if(!unitTarget)
4890 return;
4892 uint32 spellId;
4893 switch(rand()%4)
4895 case 0:
4896 spellId=46740;
4897 break;
4898 case 1:
4899 spellId=46739;
4900 break;
4901 case 2:
4902 spellId=46738;
4903 break;
4904 case 3:
4905 spellId=46736;
4906 break;
4908 unitTarget->CastSpell(unitTarget, spellId, true);
4909 break;
4911 //5,000 Gold
4912 case 46642:
4914 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4915 return;
4917 ((Player*)unitTarget)->ModifyMoney(50000000);
4919 break;
4921 case 51770:
4923 if(!unitTarget)
4924 return;
4926 unitTarget->CastSpell(unitTarget,51771,false);
4927 break;
4930 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER )
4932 switch(m_spellInfo->Id)
4934 // Chimera Shot
4935 case 53209:
4937 uint32 spellId = 0;
4938 int32 basePoint = 0;
4939 Unit::AuraMap& Auras = unitTarget->GetAuras();
4940 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
4942 Aura *aura = (*i).second;
4943 if (aura->GetCasterGUID() != m_caster->GetGUID())
4944 continue;
4945 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
4946 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
4947 if (!(familyFlag & 0x000000800000C000LL))
4948 continue;
4949 // Refresh aura duration
4950 aura->SetAuraDuration(aura->GetAuraMaxDuration());
4951 aura->SendAuraUpdate(false);
4953 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
4954 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
4956 spellId = 53353; // 53353 Chimera Shot - Serpent
4957 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
4959 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
4960 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
4962 spellId = 53358; // 53358 Chimera Shot - Viper
4963 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
4965 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
4966 if (familyFlag & 0x0000000000008000LL)
4967 spellId = 53359; // 53359 Chimera Shot - Scorpid
4968 // ?? nothing say in spell desc (possibly need addition check)
4969 //if (familyFlag & 0x0000010000000000LL || // dot
4970 // familyFlag & 0x0000100000000000LL) // stun
4972 // spellId = 53366; // 53366 Chimera Shot - Wyvern
4975 if (spellId)
4976 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
4977 return;
4979 default:
4980 break;
4983 else if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4985 switch(m_spellInfo->SpellFamilyFlags)
4987 // Judgement
4988 case 0x800000:
4990 if(!unitTarget || !unitTarget->isAlive())
4991 return;
4992 uint32 spellId2 = 0;
4994 // all seals have aura dummy
4995 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4996 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4998 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5000 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5001 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
5002 continue;
5004 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
5005 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
5007 if(spellId2 <= 1)
5008 continue;
5010 // found, remove seal
5011 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
5013 // Sanctified Judgement
5014 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5015 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
5017 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
5019 int32 chance = (*i)->GetModifier()->m_amount;
5020 if ( roll_chance_i(chance) )
5022 int32 mana = spellInfo->manaCost;
5023 if ( Player* modOwner = m_caster->GetSpellModOwner() )
5024 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
5025 mana = int32(mana* 0.8f);
5026 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
5028 break;
5032 break;
5035 m_caster->CastSpell(unitTarget,spellId2,true);
5036 return;
5041 // normal DB scripted effect
5042 if(!unitTarget)
5043 return;
5045 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5046 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5049 void Spell::EffectSanctuary(uint32 /*i*/)
5051 if(!unitTarget)
5052 return;
5053 //unitTarget->CombatStop();
5055 unitTarget->CombatStop();
5056 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5057 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5058 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5060 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5064 void Spell::EffectAddComboPoints(uint32 /*i*/)
5066 if(!unitTarget)
5067 return;
5069 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5070 return;
5072 if(damage <= 0)
5073 return;
5075 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5078 void Spell::EffectDuel(uint32 i)
5080 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5081 return;
5083 Player *caster = (Player*)m_caster;
5084 Player *target = (Player*)unitTarget;
5086 // caster or target already have requested duel
5087 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5088 return;
5090 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5091 // Don't have to check the target's map since you cannot challenge someone across maps
5092 uint32 mapid = caster->GetMapId();
5093 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5095 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5096 return;
5099 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5100 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5102 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5103 return;
5106 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5107 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5109 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5110 return;
5113 //CREATE DUEL FLAG OBJECT
5114 GameObject* pGameObj = new GameObject;
5116 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5118 Map *map = m_caster->GetMap();
5119 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
5120 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5121 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5122 m_caster->GetPositionZ(),
5123 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5125 delete pGameObj;
5126 return;
5129 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5130 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5131 int32 duration = GetSpellDuration(m_spellInfo);
5132 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5133 pGameObj->SetSpellId(m_spellInfo->Id);
5135 m_caster->AddGameObject(pGameObj);
5136 map->Add(pGameObj);
5137 //END
5139 // Send request
5140 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5141 data << pGameObj->GetGUID();
5142 data << caster->GetGUID();
5143 caster->GetSession()->SendPacket(&data);
5144 target->GetSession()->SendPacket(&data);
5146 // create duel-info
5147 DuelInfo *duel = new DuelInfo;
5148 duel->initiator = caster;
5149 duel->opponent = target;
5150 duel->startTime = 0;
5151 duel->startTimer = 0;
5152 caster->duel = duel;
5154 DuelInfo *duel2 = new DuelInfo;
5155 duel2->initiator = caster;
5156 duel2->opponent = caster;
5157 duel2->startTime = 0;
5158 duel2->startTimer = 0;
5159 target->duel = duel2;
5161 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5162 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5165 void Spell::EffectStuck(uint32 /*i*/)
5167 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5168 return;
5170 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5171 return;
5173 Player* pTarget = (Player*)unitTarget;
5175 sLog.outDebug("Spell Effect: Stuck");
5176 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());
5178 if(pTarget->isInFlight())
5179 return;
5181 // homebind location is loaded always
5182 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5184 // Stuck spell trigger Hearthstone cooldown
5185 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5186 if(!spellInfo)
5187 return;
5188 Spell spell(pTarget,spellInfo,true,0);
5189 spell.SendSpellCooldown();
5192 void Spell::EffectSummonPlayer(uint32 /*i*/)
5194 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5195 return;
5197 // Evil Twin (ignore player summon, but hide this for summoner)
5198 if(unitTarget->GetDummyAura(23445))
5199 return;
5201 float x,y,z;
5202 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5204 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5206 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5207 data << uint64(m_caster->GetGUID()); // summoner guid
5208 data << uint32(m_caster->GetZoneId()); // summoner zone
5209 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5210 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5213 static ScriptInfo generateActivateCommand()
5215 ScriptInfo si;
5216 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5217 return si;
5220 void Spell::EffectActivateObject(uint32 effect_idx)
5222 if(!gameObjTarget)
5223 return;
5225 static ScriptInfo activateCommand = generateActivateCommand();
5227 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5229 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5232 void Spell::EffectApplyGlyph(uint32 i)
5234 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5235 return;
5237 Player *player = (Player*)m_caster;
5239 // remove old glyph
5240 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5242 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5244 player->RemoveAurasDueToSpell(old_gp->SpellId);
5245 player->SetGlyph(m_glyphIndex, 0);
5249 // apply new one
5250 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5252 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5254 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5256 if(gp->TypeFlags != gs->TypeFlags)
5258 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5259 return; // glyph slot missmatch
5263 player->CastSpell(m_caster, gp->SpellId, true);
5264 player->SetGlyph(m_glyphIndex, glyph);
5269 void Spell::EffectSummonTotem(uint32 i)
5271 uint8 slot = 0;
5272 switch(m_spellInfo->EffectMiscValueB[i])
5274 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5275 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5276 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5277 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5278 // Battle standard case
5279 case SUMMON_TYPE_TOTEM: slot = 254; break;
5280 // jewelery statue case, like totem without slot
5281 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5282 default: return;
5285 if(slot < MAX_TOTEM)
5287 uint64 guid = m_caster->m_TotemSlot[slot];
5288 if(guid != 0)
5290 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5291 if(OldTotem && OldTotem->isTotem())
5292 ((Totem*)OldTotem)->UnSummon();
5296 uint32 team = 0;
5297 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5298 team = ((Player*)m_caster)->GetTeam();
5300 Totem* pTotem = new Totem;
5302 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5304 delete pTotem;
5305 return;
5308 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5310 float x,y,z;
5311 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5313 // totem must be at same Z in case swimming caster and etc.
5314 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5315 z = m_caster->GetPositionZ();
5317 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5319 if(slot < MAX_TOTEM)
5320 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5322 pTotem->SetOwner(m_caster->GetGUID());
5323 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5325 int32 duration=GetSpellDuration(m_spellInfo);
5326 if(Player* modOwner = m_caster->GetSpellModOwner())
5327 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5328 pTotem->SetDuration(duration);
5330 if (damage) // if not spell info, DB values used
5332 pTotem->SetMaxHealth(damage);
5333 pTotem->SetHealth(damage);
5336 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5338 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5339 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5341 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5342 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5344 pTotem->Summon(m_caster);
5346 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5348 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5349 data << uint8(slot);
5350 data << uint64(pTotem->GetGUID());
5351 data << uint32(duration);
5352 data << uint32(m_spellInfo->Id);
5353 ((Player*)m_caster)->SendDirectMessage(&data);
5357 void Spell::EffectEnchantHeldItem(uint32 i)
5359 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5360 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5361 return;
5363 Player* item_owner = (Player*)unitTarget;
5364 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5366 if(!item )
5367 return;
5369 // must be equipped
5370 if(!item ->IsEquipped())
5371 return;
5373 if (m_spellInfo->EffectMiscValue[i])
5375 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5376 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5377 if(!duration)
5378 duration = m_currentBasePoints[i]+1; //Base points after ..
5379 if(!duration)
5380 duration = 10; //10 seconds for enchants which don't have listed duration
5382 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5383 if(!pEnchant)
5384 return;
5386 // Always go to temp enchantment slot
5387 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5389 // Enchantment will not be applied if a different one already exists
5390 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5391 return;
5393 // Apply the temporary enchantment
5394 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5395 item_owner->ApplyEnchantment(item,slot,true);
5399 void Spell::EffectDisEnchant(uint32 /*i*/)
5401 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5402 return;
5404 Player* p_caster = (Player*)m_caster;
5405 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5406 return;
5408 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5410 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5412 // item will be removed at disenchanting end
5415 void Spell::EffectInebriate(uint32 /*i*/)
5417 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5418 return;
5420 Player *player = (Player*)unitTarget;
5421 uint16 currentDrunk = player->GetDrunkValue();
5422 uint16 drunkMod = damage * 256;
5423 if (currentDrunk + drunkMod > 0xFFFF)
5424 currentDrunk = 0xFFFF;
5425 else
5426 currentDrunk += drunkMod;
5427 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5430 void Spell::EffectFeedPet(uint32 i)
5432 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5433 return;
5435 Player *_player = (Player*)m_caster;
5437 if(!itemTarget)
5438 return;
5440 Pet *pet = _player->GetPet();
5441 if(!pet)
5442 return;
5444 if(!pet->isAlive())
5445 return;
5447 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5448 if(benefit <= 0)
5449 return;
5451 uint32 count = 1;
5452 _player->DestroyItemCount(itemTarget,count,true);
5453 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5455 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5458 void Spell::EffectDismissPet(uint32 /*i*/)
5460 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5461 return;
5463 Pet* pet = m_caster->GetPet();
5465 // not let dismiss dead pet
5466 if(!pet||!pet->isAlive())
5467 return;
5469 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5472 void Spell::EffectSummonObject(uint32 i)
5474 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5476 uint8 slot = 0;
5477 switch(m_spellInfo->Effect[i])
5479 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5480 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5481 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5482 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5483 default: return;
5486 uint64 guid = m_caster->m_ObjectSlot[slot];
5487 if(guid != 0)
5489 GameObject* obj = NULL;
5490 if( m_caster )
5491 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5493 if(obj) obj->Delete();
5494 m_caster->m_ObjectSlot[slot] = 0;
5497 GameObject* pGameObj = new GameObject;
5499 float rot2 = sin(m_caster->GetOrientation()/2);
5500 float rot3 = cos(m_caster->GetOrientation()/2);
5502 float x,y,z;
5503 // If dest location if present
5504 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5506 x = m_targets.m_destX;
5507 y = m_targets.m_destY;
5508 z = m_targets.m_destZ;
5510 // Summon in random point all other units if location present
5511 else
5512 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5514 Map *map = m_caster->GetMap();
5515 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5517 delete pGameObj;
5518 return;
5521 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5522 int32 duration = GetSpellDuration(m_spellInfo);
5523 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5524 pGameObj->SetSpellId(m_spellInfo->Id);
5525 m_caster->AddGameObject(pGameObj);
5527 map->Add(pGameObj);
5528 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5529 data << pGameObj->GetGUID();
5530 m_caster->SendMessageToSet(&data,true);
5532 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5535 void Spell::EffectResurrect(uint32 /*effIndex*/)
5537 if(!unitTarget)
5538 return;
5539 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5540 return;
5542 if(unitTarget->isAlive())
5543 return;
5544 if(!unitTarget->IsInWorld())
5545 return;
5547 switch (m_spellInfo->Id)
5549 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5550 case 8342:
5551 if (roll_chance_i(67))
5553 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5554 return;
5556 break;
5557 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5558 case 22999:
5559 if (roll_chance_i(50))
5561 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5562 return;
5564 break;
5565 default:
5566 break;
5569 Player* pTarget = ((Player*)unitTarget);
5571 if(pTarget->isRessurectRequested()) // already have one active request
5572 return;
5574 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5575 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5577 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5578 SendResurrectRequest(pTarget);
5581 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5583 if(!unitTarget || !unitTarget->isAlive())
5584 return;
5586 if( unitTarget->m_extraAttacks )
5587 return;
5589 unitTarget->m_extraAttacks = damage;
5592 void Spell::EffectParry(uint32 /*i*/)
5594 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5595 ((Player*)unitTarget)->SetCanParry(true);
5598 void Spell::EffectBlock(uint32 /*i*/)
5600 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5601 ((Player*)unitTarget)->SetCanBlock(true);
5604 void Spell::EffectMomentMove(uint32 i)
5606 if(unitTarget->isInFlight())
5607 return;
5609 if( m_spellInfo->rangeIndex== 1) //self range
5611 uint32 mapid = m_caster->GetMapId();
5612 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5614 // before caster
5615 float fx,fy,fz;
5616 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5617 float ox,oy,oz;
5618 unitTarget->GetPosition(ox,oy,oz);
5620 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5621 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5623 fx = fx2;
5624 fy = fy2;
5625 fz = fz2;
5626 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5629 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5630 ((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));
5631 else
5632 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5636 void Spell::EffectReputation(uint32 i)
5638 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5639 return;
5641 Player *_player = (Player*)unitTarget;
5643 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5645 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5647 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5649 if(!factionEntry)
5650 return;
5652 _player->ModifyFactionReputation(factionEntry,rep_change);
5655 void Spell::EffectQuestComplete(uint32 i)
5657 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5658 return;
5660 Player *_player = (Player*)m_caster;
5662 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5663 _player->AreaExploredOrEventHappens(quest_id);
5666 void Spell::EffectSelfResurrect(uint32 i)
5668 if(!unitTarget || unitTarget->isAlive())
5669 return;
5670 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5671 return;
5672 if(!unitTarget->IsInWorld())
5673 return;
5675 uint32 health = 0;
5676 uint32 mana = 0;
5678 // flat case
5679 if(damage < 0)
5681 health = uint32(-damage);
5682 mana = m_spellInfo->EffectMiscValue[i];
5684 // percent case
5685 else
5687 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5688 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5689 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5692 Player *plr = ((Player*)unitTarget);
5693 plr->ResurrectPlayer(0.0f);
5695 plr->SetHealth( health );
5696 plr->SetPower(POWER_MANA, mana );
5697 plr->SetPower(POWER_RAGE, 0 );
5698 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5700 plr->SpawnCorpseBones();
5702 plr->SaveToDB();
5705 void Spell::EffectSkinning(uint32 /*i*/)
5707 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5708 return;
5709 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5710 return;
5712 Creature* creature = (Creature*) unitTarget;
5713 int32 targetLevel = creature->getLevel();
5715 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5717 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5718 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5720 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5722 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5724 // Double chances for elites
5725 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5728 void Spell::EffectCharge(uint32 /*i*/)
5730 if(!unitTarget || !m_caster)
5731 return;
5733 float x, y, z;
5734 unitTarget->GetContactPoint(m_caster, x, y, z);
5735 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5736 ((Creature *)unitTarget)->StopMoving();
5738 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5739 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5741 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5742 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5744 // not all charge effects used in negative spells
5745 if ( !IsPositiveSpell(m_spellInfo->Id))
5746 m_caster->Attack(unitTarget,true);
5749 void Spell::EffectSummonCritter(uint32 i)
5751 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5752 return;
5753 Player* player = (Player*)m_caster;
5755 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5756 if(!pet_entry)
5757 return;
5759 Pet* old_critter = player->GetMiniPet();
5761 // for same pet just despawn
5762 if(old_critter && old_critter->GetEntry() == pet_entry)
5764 player->RemoveMiniPet();
5765 return;
5768 // despawn old pet before summon new
5769 if(old_critter)
5770 player->RemoveMiniPet();
5772 // summon new pet
5773 Pet* critter = new Pet(MINI_PET);
5775 Map *map = m_caster->GetMap();
5776 uint32 pet_number = objmgr.GeneratePetNumber();
5777 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5778 map, pet_entry, pet_number))
5780 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5781 delete critter;
5782 return;
5785 float x,y,z;
5786 // If dest location if present
5787 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5789 x = m_targets.m_destX;
5790 y = m_targets.m_destY;
5791 z = m_targets.m_destZ;
5793 // Summon if dest location not present near caster
5794 else
5795 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5797 critter->Relocate(x,y,z,m_caster->GetOrientation());
5799 if(!critter->IsPositionValid())
5801 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5802 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5803 delete critter;
5804 return;
5807 critter->SetOwnerGUID(m_caster->GetGUID());
5808 critter->SetCreatorGUID(m_caster->GetGUID());
5809 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5810 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5812 critter->AIM_Initialize();
5813 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5814 critter->SetMaxHealth(1);
5815 critter->SetHealth(1);
5816 critter->SetLevel(1);
5818 // set timer for unsummon
5819 int32 duration = GetSpellDuration(m_spellInfo);
5820 if(duration > 0)
5821 critter->SetDuration(duration);
5823 std::string name = player->GetName();
5824 name.append(petTypeSuffix[critter->getPetType()]);
5825 critter->SetName( name );
5826 player->SetMiniPet(critter);
5828 map->Add((Creature*)critter);
5831 void Spell::EffectKnockBack(uint32 i)
5833 if(!unitTarget || !m_caster)
5834 return;
5836 // Effect only works on players
5837 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5838 return;
5840 float vsin = sin(m_caster->GetAngle(unitTarget));
5841 float vcos = cos(m_caster->GetAngle(unitTarget));
5843 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5844 data.append(unitTarget->GetPackGUID());
5845 data << uint32(0); // Sequence
5846 data << float(vcos); // x direction
5847 data << float(vsin); // y direction
5848 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5849 data << float(damage/-10); // Z Movement speed (vertical)
5851 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5854 void Spell::EffectSendTaxi(uint32 i)
5856 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5857 return;
5859 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5860 if(!entry)
5861 return;
5863 std::vector<uint32> nodes;
5865 nodes.resize(2);
5866 nodes[0] = entry->from;
5867 nodes[1] = entry->to;
5869 uint32 mountid = 0;
5870 switch(m_spellInfo->Id)
5872 case 31606: //Stormcrow Amulet
5873 mountid = 17447;
5874 break;
5875 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5876 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5877 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5878 mountid = 22840;
5879 break;
5880 case 34905: //Stealth Flight
5881 mountid = 6851;
5882 break;
5883 case 53335: //Stormwind Harbor Flight - Peaceful
5884 mountid = 6852;
5885 break;
5888 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5892 void Spell::EffectPlayerPull(uint32 i)
5894 if(!unitTarget || !m_caster)
5895 return;
5897 // Effect only works on players
5898 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5899 return;
5901 float vsin = sin(unitTarget->GetAngle(m_caster));
5902 float vcos = cos(unitTarget->GetAngle(m_caster));
5904 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5905 data.append(unitTarget->GetPackGUID());
5906 data << uint32(0); // Sequence
5907 data << float(vcos); // x direction
5908 data << float(vsin); // y direction
5909 // Horizontal speed
5910 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5911 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5913 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5916 void Spell::EffectDispelMechanic(uint32 i)
5918 if(!unitTarget)
5919 return;
5921 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5923 Unit::AuraMap& Auras = unitTarget->GetAuras();
5924 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5926 next = iter;
5927 ++next;
5928 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5929 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5931 unitTarget->RemoveAurasDueToSpell(spell->Id);
5932 if(Auras.empty())
5933 break;
5934 else
5935 next = Auras.begin();
5938 return;
5941 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5943 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5944 return;
5945 Player *_player = (Player*)m_caster;
5946 Pet *pet = _player->GetPet();
5947 if(!pet)
5948 return;
5949 if(pet->isAlive())
5950 return;
5951 if(damage < 0)
5952 return;
5953 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5954 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5955 pet->setDeathState( ALIVE );
5956 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5957 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5959 pet->AIM_Initialize();
5961 _player->PetSpellInitialize();
5962 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5965 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5967 float mana = 0;
5968 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5970 if(!m_caster->m_TotemSlot[slot])
5971 continue;
5973 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5974 if(totem && totem->isTotem())
5976 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5977 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5978 if(spellInfo)
5979 mana += spellInfo->manaCost * damage / 100;
5980 ((Totem*)totem)->UnSummon();
5984 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5985 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5988 void Spell::EffectDurabilityDamage(uint32 i)
5990 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5991 return;
5993 int32 slot = m_spellInfo->EffectMiscValue[i];
5995 // FIXME: some spells effects have value -1/-2
5996 // Possibly its mean -1 all player equipped items and -2 all items
5997 if(slot < 0)
5999 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6000 return;
6003 // invalid slot value
6004 if(slot >= INVENTORY_SLOT_BAG_END)
6005 return;
6007 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6008 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6011 void Spell::EffectDurabilityDamagePCT(uint32 i)
6013 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6014 return;
6016 int32 slot = m_spellInfo->EffectMiscValue[i];
6018 // FIXME: some spells effects have value -1/-2
6019 // Possibly its mean -1 all player equipped items and -2 all items
6020 if(slot < 0)
6022 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6023 return;
6026 // invalid slot value
6027 if(slot >= INVENTORY_SLOT_BAG_END)
6028 return;
6030 if(damage <= 0)
6031 return;
6033 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6034 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6037 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6039 if(!unitTarget)
6040 return;
6042 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6045 void Spell::EffectTransmitted(uint32 effIndex)
6047 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6049 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6051 if (!goinfo)
6053 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6054 return;
6057 float fx,fy,fz;
6059 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6061 fx = m_targets.m_destX;
6062 fy = m_targets.m_destY;
6063 fz = m_targets.m_destZ;
6065 //FIXME: this can be better check for most objects but still hack
6066 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6068 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6069 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6071 else
6073 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6074 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6075 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6077 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6080 Map *cMap = m_caster->GetMap();
6082 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6084 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6085 { // but this is not proper, we really need to ignore not materialized objects
6086 SendCastResult(SPELL_FAILED_NOT_HERE);
6087 SendChannelUpdate(0);
6088 return;
6091 // replace by water level in this case
6092 fz = cMap->GetWaterLevel(fx,fy);
6094 // if gameobject is summoning object, it should be spawned right on caster's position
6095 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6097 m_caster->GetPosition(fx,fy,fz);
6100 GameObject* pGameObj = new GameObject;
6102 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6103 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6105 delete pGameObj;
6106 return;
6109 int32 duration = GetSpellDuration(m_spellInfo);
6111 switch(goinfo->type)
6113 case GAMEOBJECT_TYPE_FISHINGNODE:
6115 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6116 // Orientation3
6117 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6118 // Orientation4
6119 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6120 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6122 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6123 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6124 int32 lastSec;
6125 switch(urand(0, 3))
6127 case 0: lastSec = 3; break;
6128 case 1: lastSec = 7; break;
6129 case 2: lastSec = 13; break;
6130 case 3: lastSec = 17; break;
6133 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6134 break;
6136 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6138 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6140 pGameObj->AddUniqueUse((Player*)m_caster);
6141 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6143 break;
6145 case GAMEOBJECT_TYPE_FISHINGHOLE:
6146 case GAMEOBJECT_TYPE_CHEST:
6147 default:
6149 break;
6153 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6155 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6157 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6158 pGameObj->SetSpellId(m_spellInfo->Id);
6160 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6161 //m_caster->AddGameObject(pGameObj);
6162 //m_ObjToDel.push_back(pGameObj);
6164 cMap->Add(pGameObj);
6166 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6167 data << uint64(pGameObj->GetGUID());
6168 m_caster->SendMessageToSet(&data,true);
6170 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6172 GameObject* linkedGO = new GameObject;
6173 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6174 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6176 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6177 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6178 linkedGO->SetSpellId(m_spellInfo->Id);
6179 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6181 linkedGO->GetMap()->Add(linkedGO);
6183 else
6185 delete linkedGO;
6186 linkedGO = NULL;
6187 return;
6192 void Spell::EffectProspecting(uint32 /*i*/)
6194 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6195 return;
6197 Player* p_caster = (Player*)m_caster;
6198 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6199 return;
6201 if(itemTarget->GetCount() < 5)
6202 return;
6204 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6206 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6207 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6208 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6211 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6214 void Spell::EffectMilling(uint32 /*i*/)
6216 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6217 return;
6219 Player* p_caster = (Player*)m_caster;
6220 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6221 return;
6223 if(itemTarget->GetCount() < 5)
6224 return;
6226 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6228 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6229 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6230 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6233 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6236 void Spell::EffectSkill(uint32 /*i*/)
6238 sLog.outDebug("WORLD: SkillEFFECT");
6241 void Spell::EffectSummonDemon(uint32 i)
6243 float px = m_targets.m_destX;
6244 float py = m_targets.m_destY;
6245 float pz = m_targets.m_destZ;
6247 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6248 if (!Charmed)
6249 return;
6251 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6252 Charmed->SetLevel(m_caster->getLevel());
6254 // TODO: Add damage/mana/hp according to level
6256 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6258 // Enslave demon effect, without mana cost and cooldown
6259 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6261 // Inferno effect
6262 Charmed->CastSpell(Charmed, 22703, true, 0);
6266 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6267 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6268 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6269 This is why we use a half sec delay between the visual effect and the resurrection itself */
6270 void Spell::EffectSpiritHeal(uint32 /*i*/)
6273 if(!unitTarget || unitTarget->isAlive())
6274 return;
6275 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6276 return;
6277 if(!unitTarget->IsInWorld())
6278 return;
6280 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6281 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6282 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6283 ((Player*)unitTarget)->SpawnCorpseBones();
6287 // remove insignia spell effect
6288 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6290 sLog.outDebug("Effect: SkinPlayerCorpse");
6291 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6292 return;
6294 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6297 void Spell::EffectStealBeneficialBuff(uint32 i)
6299 sLog.outDebug("Effect: StealBeneficialBuff");
6301 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6302 return;
6304 std::vector <Aura *> steal_list;
6305 // Create dispel mask by dispel type
6306 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6307 Unit::AuraMap const& auras = unitTarget->GetAuras();
6308 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6310 Aura *aur = (*itr).second;
6311 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6313 // Need check for passive? this
6314 if (aur->IsPositive() && !aur->IsPassive())
6315 steal_list.push_back(aur);
6318 // Ok if exist some buffs for dispel try dispel it
6319 if (!steal_list.empty())
6321 std::list < std::pair<uint32,uint64> > success_list;
6322 int32 list_size = steal_list.size();
6323 // Dispell N = damage buffs (or while exist buffs for dispel)
6324 for (int32 count=0; count < damage && list_size > 0; ++count)
6326 // Random select buff for dispel
6327 Aura *aur = steal_list[urand(0, list_size-1)];
6328 // Not use chance for steal
6329 // TODO possible need do it
6330 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6332 // Remove buff from list for prevent doubles
6333 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6335 Aura *stealed = *j;
6336 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6338 j = steal_list.erase(j);
6339 --list_size;
6341 else
6342 ++j;
6345 // Really try steal and send log
6346 if (!success_list.empty())
6348 int32 count = success_list.size();
6349 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6350 data.append(unitTarget->GetPackGUID()); // Victim GUID
6351 data.append(m_caster->GetPackGUID()); // Caster GUID
6352 data << uint32(m_spellInfo->Id); // Dispell spell id
6353 data << uint8(0); // not used
6354 data << uint32(count); // count
6355 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6357 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6358 data << uint32(spellInfo->Id); // Spell Id
6359 data << uint8(0); // 0 - steals !=0 transfers
6360 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6362 m_caster->SendMessageToSet(&data, true);
6367 void Spell::EffectKillCredit(uint32 i)
6369 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6370 return;
6372 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6375 void Spell::EffectQuestFail(uint32 i)
6377 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6378 return;
6380 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6383 void Spell::EffectActivateRune(uint32 i)
6385 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6386 return;
6388 Player *plr = (Player*)m_caster;
6390 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6391 return;
6393 for(uint32 j = 0; j < MAX_RUNES; ++j)
6395 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[i])
6397 plr->SetRuneCooldown(j, 0);
6402 void Spell::EffectTitanGrip(uint32 i)
6404 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6405 ((Player*)unitTarget)->SetCanTitanGrip(true);