[7022] Added support for packets > 64 kb
[getmangos.git] / src / game / SpellEffects.cpp
blobd05099fece05cbb69c066bd08cd0fc60f0900c87
1 /*
2 * Copyright (C) 2005-2009 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;
1463 switch(m_spellInfo->Id)
1465 case 23989: //Readiness talent
1467 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1468 return;
1470 //immediately finishes the cooldown for hunter abilities
1471 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1472 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1474 uint32 classspell = itr->first;
1475 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1477 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1479 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1481 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1482 data << uint32(classspell);
1483 data << uint64(m_caster->GetGUID());
1484 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1487 return;
1489 case 37506: // Scatter Shot
1491 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1492 return;
1494 // break Auto Shot and autohit
1495 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1496 m_caster->AttackStop();
1497 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1498 return;
1501 break;
1502 case SPELLFAMILY_PALADIN:
1503 switch(m_spellInfo->SpellIconID)
1505 case 156: // Holy Shock
1507 if(!unitTarget)
1508 return;
1510 int hurt = 0;
1511 int heal = 0;
1513 switch(m_spellInfo->Id)
1515 case 20473: hurt = 25912; heal = 25914; break;
1516 case 20929: hurt = 25911; heal = 25913; break;
1517 case 20930: hurt = 25902; heal = 25903; break;
1518 case 27174: hurt = 27176; heal = 27175; break;
1519 case 33072: hurt = 33073; heal = 33074; break;
1520 default:
1521 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1522 return;
1525 if(m_caster->IsFriendlyTo(unitTarget))
1526 m_caster->CastSpell(unitTarget, heal, true, 0);
1527 else
1528 m_caster->CastSpell(unitTarget, hurt, true, 0);
1530 return;
1532 case 561: // Judgement of command
1534 if(!unitTarget)
1535 return;
1537 uint32 spell_id = m_currentBasePoints[i]+1;
1538 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1539 if(!spell_proto)
1540 return;
1542 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1544 // decreased damage (/2) for non-stunned target.
1545 SpellModifier *mod = new SpellModifier;
1546 mod->op = SPELLMOD_DAMAGE;
1547 mod->value = -50;
1548 mod->type = SPELLMOD_PCT;
1549 mod->spellId = m_spellInfo->Id;
1550 mod->mask = 0x0000020000000000LL;
1551 mod->mask2= 0LL;
1553 ((Player*)m_caster)->AddSpellMod(mod, true);
1554 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1555 // mod deleted
1556 ((Player*)m_caster)->AddSpellMod(mod, false);
1558 else
1559 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1561 return;
1565 switch(m_spellInfo->Id)
1567 case 31789: // Righteous Defense (step 1)
1569 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1571 // non-standard cast requirement check
1572 if (!unitTarget || unitTarget->getAttackers().empty())
1574 // clear cooldown at fail
1575 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1577 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1579 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1580 data << uint32(m_spellInfo->Id);
1581 data << uint64(m_caster->GetGUID());
1582 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1585 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1586 return;
1589 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1590 // Clear targets for eff 1
1591 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1592 ihit->effectMask &= ~(1<<1);
1594 // not empty (checked)
1595 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1597 // chance to be selected from list
1598 float chance = 100.0f/attackers.size();
1599 uint32 count=0;
1600 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1602 if(!roll_chance_f(chance))
1603 continue;
1604 ++count;
1605 AddUnitTarget((*aItr), 1);
1608 // now let next effect cast spell at each target.
1609 return;
1611 case 37877: // Blessing of Faith
1613 if(!unitTarget)
1614 return;
1616 uint32 spell_id = 0;
1617 switch(unitTarget->getClass())
1619 case CLASS_DRUID: spell_id = 37878; break;
1620 case CLASS_PALADIN: spell_id = 37879; break;
1621 case CLASS_PRIEST: spell_id = 37880; break;
1622 case CLASS_SHAMAN: spell_id = 37881; break;
1623 default: return; // ignore for not healing classes
1626 m_caster->CastSpell(m_caster,spell_id,true);
1627 return;
1630 break;
1631 case SPELLFAMILY_SHAMAN:
1632 //Shaman Rockbiter Weapon
1633 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1635 uint32 spell_id = 0;
1636 switch(m_spellInfo->Id)
1638 case 8017: spell_id = 36494; break; // Rank 1
1639 case 8018: spell_id = 36750; break; // Rank 2
1640 case 8019: spell_id = 36755; break; // Rank 3
1641 case 10399: spell_id = 36759; break; // Rank 4
1642 case 16314: spell_id = 36763; break; // Rank 5
1643 case 16315: spell_id = 36766; break; // Rank 6
1644 case 16316: spell_id = 36771; break; // Rank 7
1645 case 25479: spell_id = 36775; break; // Rank 8
1646 case 25485: spell_id = 36499; break; // Rank 9
1647 default:
1648 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1649 return;
1652 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1654 if(!spellInfo)
1656 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1657 return;
1660 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1661 return;
1663 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1665 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1667 if(item->IsFitToSpellRequirements(m_spellInfo))
1669 Spell *spell = new Spell(m_caster, spellInfo, true);
1671 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1672 // at calculation applied affect from Elemental Weapons talent
1673 // real enchantment damage-1
1674 spell->m_currentBasePoints[1] = damage-1;
1676 SpellCastTargets targets;
1677 targets.setItemTarget( item );
1678 spell->prepare(&targets);
1682 return;
1685 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1687 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1688 return;
1690 // Regenerate 6% of Total Mana Every 3 secs
1691 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1692 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1693 return;
1696 break;
1699 // pet auras
1700 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1702 m_caster->AddPetAura(petSpell);
1703 return;
1707 void Spell::EffectTriggerSpellWithValue(uint32 i)
1709 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1711 // normal case
1712 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1714 if(!spellInfo)
1716 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1717 return;
1720 int32 bp = damage;
1721 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1724 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1726 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1727 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1729 if(!spellInfo)
1731 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1732 return;
1735 finish();
1736 Spell *spell = new Spell(m_caster, spellInfo, true);
1738 SpellCastTargets targets;
1739 targets.setUnitTarget( unitTarget);
1740 spell->prepare(&targets);
1742 m_caster->SetCurrentCastedSpell(spell);
1743 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1747 void Spell::EffectForceCast(uint32 i)
1749 if( !unitTarget )
1750 return;
1752 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1754 // normal case
1755 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1757 if(!spellInfo)
1759 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1760 return;
1763 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1766 void Spell::EffectTriggerSpell(uint32 i)
1768 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1770 // special cases
1771 switch(triggered_spell_id)
1773 // Vanish
1774 case 18461:
1776 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1777 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1778 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1780 // if this spell is given to NPC it must handle rest by it's own AI
1781 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1782 return;
1784 // get highest rank of the Stealth spell
1785 uint32 spellId = 0;
1786 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1787 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1789 // only highest rank is shown in spell book, so simply check if shown in spell book
1790 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1791 continue;
1793 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1794 if (!spellInfo)
1795 continue;
1797 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1799 spellId = spellInfo->Id;
1800 break;
1804 // no Stealth spell found
1805 if (!spellId)
1806 return;
1808 // reset cooldown on it if needed
1809 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1810 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1812 m_caster->CastSpell(m_caster, spellId, true);
1813 return;
1815 // just skip
1816 case 23770: // Sayge's Dark Fortune of *
1817 // not exist, common cooldown can be implemented in scripts if need.
1818 return;
1819 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1820 case 29284:
1822 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1823 if (!spell)
1824 return;
1826 for (int i=0; i < spell->StackAmount; ++i)
1827 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1828 return;
1830 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1831 case 29286:
1833 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1834 if (!spell)
1835 return;
1837 for (int i=0; i < spell->StackAmount; ++i)
1838 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1839 return;
1841 // Righteous Defense
1842 case 31980:
1844 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1845 return;
1847 // Cloak of Shadows
1848 case 35729 :
1850 Unit::AuraMap& Auras = m_caster->GetAuras();
1851 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1853 // remove all harmful spells on you...
1854 if( // ignore positive and passive auras
1855 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1856 // ignore physical auras
1857 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1858 // ignore immunity persistent spells
1859 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1861 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1862 iter = Auras.begin();
1865 return;
1867 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1868 case 41967:
1870 if (Unit *pet = m_caster->GetPet())
1871 pet->CastSpell(pet, 28305, true);
1872 return;
1876 // normal case
1877 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1879 if(!spellInfo)
1881 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1882 return;
1885 // some triggered spells require specific equipment
1886 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1888 // main hand weapon required
1889 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1891 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1893 // skip spell if no weapon in slot or broken
1894 if(!item || item->IsBroken() )
1895 return;
1897 // skip spell if weapon not fit to triggered spell
1898 if(!item->IsFitToSpellRequirements(spellInfo))
1899 return;
1902 // offhand hand weapon required
1903 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1905 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1907 // skip spell if no weapon in slot or broken
1908 if(!item || item->IsBroken() )
1909 return;
1911 // skip spell if weapon not fit to triggered spell
1912 if(!item->IsFitToSpellRequirements(spellInfo))
1913 return;
1917 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1918 bool instant = false;
1919 for(uint32 j = i+1; j < 3; ++j)
1921 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1923 instant = true;
1924 break;
1928 if(instant)
1930 if (unitTarget)
1931 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1933 else
1934 m_TriggerSpells.push_back(spellInfo);
1937 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1939 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1941 // normal case
1942 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1944 if(!spellInfo)
1946 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
1947 m_spellInfo->Id,effect_idx,triggered_spell_id);
1948 return;
1951 if (m_CastItem)
1952 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1954 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1956 SpellCastTargets targets;
1957 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1958 spell->m_CastItem = m_CastItem;
1959 spell->prepare(&targets, NULL);
1962 void Spell::EffectTeleportUnits(uint32 i)
1964 if(!unitTarget || unitTarget->isInFlight())
1965 return;
1967 switch (m_spellInfo->EffectImplicitTargetB[i])
1969 case TARGET_INNKEEPER_COORDINATES:
1971 // Only players can teleport to innkeeper
1972 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1973 return;
1975 ((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);
1976 return;
1978 case TARGET_TABLE_X_Y_Z_COORDINATES:
1980 // TODO: Only players can teleport?
1981 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1982 return;
1983 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1984 if(!st)
1986 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1987 return;
1989 ((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);
1990 break;
1992 case TARGET_BEHIND_VICTIM:
1994 // Get selected target for player (or victim for units)
1995 Unit *pTarget = NULL;
1996 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1997 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1998 else
1999 pTarget = m_caster->getVictim();
2000 // No target present - return
2001 if (!pTarget)
2002 return;
2003 // Init dest coordinates
2004 uint32 mapid = m_caster->GetMapId();
2005 float x = m_targets.m_destX;
2006 float y = m_targets.m_destY;
2007 float z = m_targets.m_destZ;
2008 float orientation = pTarget->GetOrientation();
2009 // Teleport
2010 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2011 ((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));
2012 else
2014 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
2015 WorldPacket data;
2016 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
2017 unitTarget->SendMessageToSet(&data, false);
2019 return;
2021 default:
2023 // If not exist data for dest location - return
2024 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2026 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2027 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 = unitTarget->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;
2049 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2050 switch ( m_spellInfo->Id )
2052 // Dimensional Ripper - Everlook
2053 case 23442:
2055 int32 r = irand(0, 119);
2056 if ( r >= 70 ) // 7/12 success
2058 if ( r < 100 ) // 4/12 evil twin
2059 m_caster->CastSpell(m_caster,23445,true);
2060 else // 1/12 fire
2061 m_caster->CastSpell(m_caster,23449,true);
2063 return;
2065 // Ultrasafe Transporter: Toshley's Station
2066 case 36941:
2068 if ( roll_chance_i(50) ) // 50% success
2070 int32 rand_eff = urand(1,7);
2071 switch ( rand_eff )
2073 case 1:
2074 // soul split - evil
2075 m_caster->CastSpell(m_caster,36900,true);
2076 break;
2077 case 2:
2078 // soul split - good
2079 m_caster->CastSpell(m_caster,36901,true);
2080 break;
2081 case 3:
2082 // Increase the size
2083 m_caster->CastSpell(m_caster,36895,true);
2084 break;
2085 case 4:
2086 // Decrease the size
2087 m_caster->CastSpell(m_caster,36893,true);
2088 break;
2089 case 5:
2090 // Transform
2092 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2093 m_caster->CastSpell(m_caster,36897,true);
2094 else
2095 m_caster->CastSpell(m_caster,36899,true);
2096 break;
2098 case 6:
2099 // chicken
2100 m_caster->CastSpell(m_caster,36940,true);
2101 break;
2102 case 7:
2103 // evil twin
2104 m_caster->CastSpell(m_caster,23445,true);
2105 break;
2108 return;
2110 // Dimensional Ripper - Area 52
2111 case 36890:
2113 if ( roll_chance_i(50) ) // 50% success
2115 int32 rand_eff = urand(1,4);
2116 switch ( rand_eff )
2118 case 1:
2119 // soul split - evil
2120 m_caster->CastSpell(m_caster,36900,true);
2121 break;
2122 case 2:
2123 // soul split - good
2124 m_caster->CastSpell(m_caster,36901,true);
2125 break;
2126 case 3:
2127 // Increase the size
2128 m_caster->CastSpell(m_caster,36895,true);
2129 break;
2130 case 4:
2131 // Transform
2133 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2134 m_caster->CastSpell(m_caster,36897,true);
2135 else
2136 m_caster->CastSpell(m_caster,36899,true);
2137 break;
2141 return;
2146 void Spell::EffectApplyAura(uint32 i)
2148 if(!unitTarget)
2149 return;
2151 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2152 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2153 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2154 return;
2156 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2157 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2158 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2159 return;
2161 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2162 if(!caster)
2163 return;
2165 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2167 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2169 // Now Reduce spell duration using data received at spell hit
2170 int32 duration = Aur->GetAuraMaxDuration();
2171 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2172 Aur->setDiminishGroup(m_diminishGroup);
2174 // if Aura removed and deleted, do not continue.
2175 if(duration== 0 && !(Aur->IsPermanent()))
2177 delete Aur;
2178 return;
2181 if(duration != Aur->GetAuraMaxDuration())
2183 Aur->SetAuraMaxDuration(duration);
2184 Aur->SetAuraDuration(duration);
2187 bool added = unitTarget->AddAura(Aur);
2189 // Aura not added and deleted in AddAura call;
2190 if (!added)
2191 return;
2193 // found crash at character loading, broken pointer to Aur...
2194 // Aur was deleted in AddAura()...
2195 if(!Aur)
2196 return;
2198 // TODO Make a way so it works for every related spell!
2199 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2201 uint32 spellId = 0;
2202 if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2203 spellId = 11196; // Recently Bandaged
2204 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2205 spellId = 23230; // Blood Fury - Healing Reduction
2207 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2208 if (AdditionalSpellInfo)
2210 // applied at target by target
2211 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2212 unitTarget->AddAura(AdditionalAura);
2213 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2217 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2218 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2219 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2222 void Spell::EffectUnlearnSpecialization( uint32 i )
2224 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2225 return;
2227 Player *_player = (Player*)unitTarget;
2228 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2230 _player->removeSpell(spellToUnlearn);
2232 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2235 void Spell::EffectPowerDrain(uint32 i)
2237 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2238 return;
2240 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2242 if(!unitTarget)
2243 return;
2244 if(!unitTarget->isAlive())
2245 return;
2246 if(unitTarget->getPowerType() != drain_power)
2247 return;
2248 if(damage < 0)
2249 return;
2251 uint32 curPower = unitTarget->GetPower(drain_power);
2253 //add spell damage bonus
2254 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2256 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2257 uint32 power = damage;
2258 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2259 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2261 int32 new_damage;
2262 if(curPower < power)
2263 new_damage = curPower;
2264 else
2265 new_damage = power;
2267 unitTarget->ModifyPower(drain_power,-new_damage);
2269 if(drain_power == POWER_MANA)
2271 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2272 if(manaMultiplier==0)
2273 manaMultiplier = 1;
2275 if(Player *modOwner = m_caster->GetSpellModOwner())
2276 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2278 int32 gain = int32(new_damage*manaMultiplier);
2280 m_caster->ModifyPower(POWER_MANA,gain);
2281 //send log
2282 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2286 void Spell::EffectSendEvent(uint32 EffectIndex)
2288 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2290 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2291 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2293 switch(m_spellInfo->Id)
2295 case 23333: // Pickup Horde Flag
2296 /*do not uncomment .
2297 if(bg->GetTypeID()==BATTLEGROUND_WS)
2298 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2299 sLog.outDebug("Send Event Horde Flag Picked Up");
2300 break;
2301 /* not used :
2302 case 23334: // Drop Horde Flag
2303 if(bg->GetTypeID()==BATTLEGROUND_WS)
2304 bg->EventPlayerDroppedFlag((Player*)m_caster);
2305 sLog.outDebug("Drop Horde Flag");
2306 break;
2308 case 23335: // Pickup Alliance Flag
2309 /*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
2310 if(bg->GetTypeID()==BATTLEGROUND_WS)
2311 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2312 sLog.outDebug("Send Event Alliance Flag Picked Up");
2313 break;
2314 /* not used :
2315 case 23336: // Drop Alliance Flag
2316 if(bg->GetTypeID()==BATTLEGROUND_WS)
2317 bg->EventPlayerDroppedFlag((Player*)m_caster);
2318 sLog.outDebug("Drop Alliance Flag");
2319 break;
2320 case 23385: // Alliance Flag Returns
2321 if(bg->GetTypeID()==BATTLEGROUND_WS)
2322 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2323 sLog.outDebug("Alliance Flag Returned");
2324 break;
2325 case 23386: // Horde Flag Returns
2326 if(bg->GetTypeID()==BATTLEGROUND_WS)
2327 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2328 sLog.outDebug("Horde Flag Returned");
2329 break;*/
2330 case 34976:
2332 if(bg->GetTypeID()==BATTLEGROUND_EY)
2333 bg->EventPlayerClickedOnFlag((Player*)m_caster, gameObjTarget);
2335 break;
2336 default:
2337 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2338 break;
2342 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2343 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2346 void Spell::EffectPowerBurn(uint32 i)
2348 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2349 return;
2351 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2353 if(!unitTarget)
2354 return;
2355 if(!unitTarget->isAlive())
2356 return;
2357 if(unitTarget->getPowerType()!=powertype)
2358 return;
2359 if(damage < 0)
2360 return;
2362 int32 curPower = int32(unitTarget->GetPower(powertype));
2364 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2365 uint32 power = damage;
2366 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2367 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2369 int32 new_damage = (curPower < power) ? curPower : power;
2371 unitTarget->ModifyPower(powertype,-new_damage);
2372 float multiplier = m_spellInfo->EffectMultipleValue[i];
2374 if(Player *modOwner = m_caster->GetSpellModOwner())
2375 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2377 new_damage = int32(new_damage*multiplier);
2378 m_damage+=new_damage;
2381 void Spell::EffectHeal( uint32 /*i*/ )
2383 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2385 // Try to get original caster
2386 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2388 // Skip if m_originalCaster not available
2389 if (!caster)
2390 return;
2392 int32 addhealth = damage;
2394 // Vessel of the Naaru (Vial of the Sunwell trinket)
2395 if (m_spellInfo->Id == 45064)
2397 // Amount of heal - depends from stacked Holy Energy
2398 int damageAmount = 0;
2399 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2400 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2401 if((*i)->GetId() == 45062)
2402 damageAmount+=(*i)->GetModifier()->m_amount;
2403 if (damageAmount)
2404 m_caster->RemoveAurasDueToSpell(45062);
2406 addhealth += damageAmount;
2408 // Swiftmend - consumes Regrowth or Rejuvenation
2409 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2411 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2412 // find most short by duration
2413 Aura *targetAura = NULL;
2414 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2416 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2417 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2419 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2420 targetAura = *i;
2424 if(!targetAura)
2426 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2427 return;
2429 int idx = 0;
2430 while(idx < 3)
2432 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2433 break;
2434 idx++;
2437 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2438 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2439 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2441 addhealth += tickheal * tickcount;
2443 else
2444 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2446 m_healing+=addhealth;
2450 void Spell::EffectHealPct( uint32 /*i*/ )
2452 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2454 // Try to get original caster
2455 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2457 // Skip if m_originalCaster not available
2458 if (!caster)
2459 return;
2461 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2462 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2464 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2465 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2467 if(caster->GetTypeId()==TYPEID_PLAYER)
2468 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2469 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2473 void Spell::EffectHealMechanical( uint32 /*i*/ )
2475 // Mechanic creature type should be correctly checked by targetCreatureType field
2476 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2478 // Try to get original caster
2479 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2481 // Skip if m_originalCaster not available
2482 if (!caster)
2483 return;
2485 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2486 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2487 unitTarget->ModifyHealth( int32(damage) );
2491 void Spell::EffectHealthLeech(uint32 i)
2493 if(!unitTarget)
2494 return;
2495 if(!unitTarget->isAlive())
2496 return;
2498 if(damage < 0)
2499 return;
2501 sLog.outDebug("HealthLeech :%i", damage);
2503 float multiplier = m_spellInfo->EffectMultipleValue[i];
2505 if(Player *modOwner = m_caster->GetSpellModOwner())
2506 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2508 int32 new_damage = int32(damage*multiplier);
2509 uint32 curHealth = unitTarget->GetHealth();
2510 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2511 if(curHealth < new_damage)
2512 new_damage = curHealth;
2514 if(m_caster->isAlive())
2516 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2518 m_caster->ModifyHealth(new_damage);
2520 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2521 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2523 // m_healthLeech+=tmpvalue;
2524 // m_damage+=new_damage;
2527 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2529 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2530 return;
2532 Player* player = (Player*)unitTarget;
2534 uint32 newitemid = itemtype;
2535 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2536 if(!pProto)
2538 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2539 return;
2542 uint32 num_to_add;
2544 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2545 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2547 int32 basePoints = m_currentBasePoints[i];
2548 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2549 if (randomPoints)
2550 num_to_add = basePoints + irand(1, randomPoints);
2551 else
2552 num_to_add = basePoints + 1;
2554 else if (pProto->MaxCount == 1)
2555 num_to_add = 1;
2556 else if(player->getLevel() >= m_spellInfo->spellLevel)
2558 int32 basePoints = m_currentBasePoints[i];
2559 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2560 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2562 else
2563 num_to_add = 2;
2565 if (num_to_add < 1)
2566 num_to_add = 1;
2567 if (num_to_add > pProto->GetMaxStackSize())
2568 num_to_add = pProto->GetMaxStackSize();
2570 // init items_count to 1, since 1 item will be created regardless of specialization
2571 int items_count=1;
2572 // the chance to create additional items
2573 float additionalCreateChance=0.0f;
2574 // the maximum number of created additional items
2575 uint8 additionalMaxNum=0;
2576 // get the chance and maximum number for creating extra items
2577 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2579 // roll with this chance till we roll not to create or we create the max num
2580 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2581 ++items_count;
2584 // really will be created more items
2585 num_to_add *= items_count;
2587 // can the player store the new item?
2588 ItemPosCountVec dest;
2589 uint32 no_space = 0;
2590 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2591 if( msg != EQUIP_ERR_OK )
2593 // convert to possible store amount
2594 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2595 num_to_add -= no_space;
2596 else
2598 // if not created by another reason from full inventory or unique items amount limitation
2599 player->SendEquipError( msg, NULL, NULL );
2600 return;
2604 if(num_to_add)
2606 // create the new item and store it
2607 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2609 // was it successful? return error if not
2610 if(!pItem)
2612 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2613 return;
2616 // set the "Crafted by ..." property of the item
2617 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2618 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2620 // send info to the client
2621 if(pItem)
2622 player->SendNewItem(pItem, num_to_add, true, true);
2624 // we succeeded in creating at least one item, so a levelup is possible
2625 player->UpdateCraftSkill(m_spellInfo->Id);
2628 // for battleground marks send by mail if not add all expected
2629 if(no_space > 0 )
2631 BattleGroundTypeId bgType;
2632 switch(m_spellInfo->Id)
2634 case SPELL_AV_MARK_WINNER:
2635 case SPELL_AV_MARK_LOSER:
2636 bgType = BATTLEGROUND_AV;
2637 break;
2638 case SPELL_WS_MARK_WINNER:
2639 case SPELL_WS_MARK_LOSER:
2640 bgType = BATTLEGROUND_WS;
2641 break;
2642 case SPELL_AB_MARK_WINNER:
2643 case SPELL_AB_MARK_LOSER:
2644 bgType = BATTLEGROUND_AB;
2645 break;
2646 default:
2647 return;
2650 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2651 bg->SendRewardMarkByMail(player,newitemid,no_space);
2655 void Spell::EffectCreateItem(uint32 i)
2657 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2660 void Spell::EffectPersistentAA(uint32 i)
2662 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2664 if(Player* modOwner = m_caster->GetSpellModOwner())
2665 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2667 int32 duration = GetSpellDuration(m_spellInfo);
2668 DynamicObject* dynObj = new DynamicObject;
2669 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))
2671 delete dynObj;
2672 return;
2674 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2675 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2676 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2677 m_caster->AddDynObject(dynObj);
2678 dynObj->GetMap()->Add(dynObj);
2681 void Spell::EffectEnergize(uint32 i)
2683 if(!unitTarget)
2684 return;
2685 if(!unitTarget->isAlive())
2686 return;
2688 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2689 return;
2691 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2693 // Some level depends spells
2694 int multiplier = 0;
2695 int level_diff = 0;
2696 switch (m_spellInfo->Id)
2698 // Restore Energy
2699 case 9512:
2700 level_diff = m_caster->getLevel() - 40;
2701 multiplier = 2;
2702 break;
2703 // Blood Fury
2704 case 24571:
2705 level_diff = m_caster->getLevel() - 60;
2706 multiplier = 10;
2707 break;
2708 // Burst of Energy
2709 case 24532:
2710 level_diff = m_caster->getLevel() - 60;
2711 multiplier = 4;
2712 break;
2713 default:
2714 break;
2717 if (level_diff > 0)
2718 damage -= multiplier * level_diff;
2720 if(damage < 0)
2721 return;
2723 if(unitTarget->GetMaxPower(power) == 0)
2724 return;
2726 unitTarget->ModifyPower(power,damage);
2727 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2729 // Mad Alchemist's Potion
2730 if (m_spellInfo->Id == 45051)
2732 // find elixirs on target
2733 uint32 elixir_mask = 0;
2734 Unit::AuraMap& Auras = unitTarget->GetAuras();
2735 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2737 uint32 spell_id = itr->second->GetId();
2738 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2739 elixir_mask |= mask;
2742 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2743 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2745 // get all available elixirs by mask and spell level
2746 std::vector<uint32> elixirs;
2747 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2748 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2750 if (itr->second & elixir_mask)
2752 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2753 continue;
2755 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2756 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2757 continue;
2759 elixirs.push_back(itr->first);
2763 if (!elixirs.empty())
2765 // cast random elixir on target
2766 uint32 rand_spell = urand(0,elixirs.size()-1);
2767 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2772 void Spell::EffectEnergisePct(uint32 i)
2774 if(!unitTarget)
2775 return;
2776 if(!unitTarget->isAlive())
2777 return;
2779 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2780 return;
2782 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2784 uint32 maxPower = unitTarget->GetMaxPower(power);
2785 if(maxPower == 0)
2786 return;
2788 uint32 gain = damage * maxPower / 100;
2789 unitTarget->ModifyPower(power, gain);
2790 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2793 void Spell::SendLoot(uint64 guid, LootType loottype)
2795 Player* player = (Player*)m_caster;
2796 if (!player)
2797 return;
2799 if (gameObjTarget)
2801 if (Script->GOHello(player, gameObjTarget))
2802 return;
2804 switch (gameObjTarget->GetGoType())
2806 case GAMEOBJECT_TYPE_DOOR:
2807 case GAMEOBJECT_TYPE_BUTTON:
2808 gameObjTarget->UseDoorOrButton();
2809 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2810 return;
2812 case GAMEOBJECT_TYPE_QUESTGIVER:
2813 // start or end quest
2814 player->PrepareQuestMenu(guid);
2815 player->SendPreparedQuest(guid);
2816 return;
2818 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2819 // triggering linked GO
2820 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2821 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2822 return;
2824 case GAMEOBJECT_TYPE_GOOBER:
2825 // goober_scripts can be triggered if the player don't have the quest
2826 if (gameObjTarget->GetGOInfo()->goober.eventId)
2828 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2829 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2832 // cast goober spell
2833 if (gameObjTarget->GetGOInfo()->goober.questId)
2834 ///Quest require to be active for GO using
2835 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2836 return;
2838 gameObjTarget->AddUniqueUse(player);
2839 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2841 //TODO? Objective counting called without spell check but with quest objective check
2842 // if send spell id then this line will duplicate to spell casting call (double counting)
2843 // So we or have this line and not required in quest_template have reqSpellIdN
2844 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2845 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2847 // triggering linked GO
2848 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2849 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2851 return;
2853 case GAMEOBJECT_TYPE_CHEST:
2854 // TODO: possible must be moved to loot release (in different from linked triggering)
2855 if (gameObjTarget->GetGOInfo()->chest.eventId)
2857 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2858 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2861 // triggering linked GO
2862 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2863 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2865 // Don't return, let loots been taken
2869 // Send loot
2870 player->SendLoot(guid, loottype);
2873 void Spell::EffectOpenLock(uint32 /*i*/)
2875 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2877 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2878 return;
2881 Player* player = (Player*)m_caster;
2883 LootType loottype = LOOT_CORPSE;
2884 uint32 lockId = 0;
2885 uint64 guid = 0;
2887 // Get lockId
2888 if(gameObjTarget)
2890 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2891 // Arathi Basin banner opening !
2892 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2893 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2895 //isAllowUseBattleGroundObject() already called in CanCast()
2896 // in battleground check
2897 if(BattleGround *bg = player->GetBattleGround())
2899 // check if it's correct bg
2900 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2901 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2902 return;
2905 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2907 //isAllowUseBattleGroundObject() already called in CanCast()
2908 // in battleground check
2909 if(BattleGround *bg = player->GetBattleGround())
2911 if(bg->GetTypeID() == BATTLEGROUND_EY)
2912 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2913 return;
2916 lockId = gameObjTarget->GetLockId();
2917 guid = gameObjTarget->GetGUID();
2919 else if(itemTarget)
2921 lockId = itemTarget->GetProto()->LockID;
2922 guid = itemTarget->GetGUID();
2924 else
2926 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2927 return;
2930 if(!lockId) // possible case for GO and maybe for items.
2932 SendLoot(guid, loottype);
2933 return;
2936 // Get LockInfo
2937 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2939 if (!lockInfo)
2941 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2942 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2943 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2944 return;
2947 // check key
2948 for(int i = 0; i < 8; ++i)
2950 // Type==1 This means lockInfo->Index[i] is an item
2951 if(lockInfo->Type[i]==LOCK_KEY_ITEM && lockInfo->Index[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[i])
2953 SendLoot(guid, loottype);
2954 return;
2958 uint32 SkillId = 0;
2959 // Check and skill-up skill
2960 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2961 SkillId = m_spellInfo->EffectMiscValue[1];
2962 // pickpocketing spells
2963 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2964 SkillId = SKILL_LOCKPICKING;
2966 // skill bonus provided by casting spell (mostly item spells)
2967 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2969 uint32 reqSkillValue = lockInfo->Skill[0];
2971 if(lockInfo->Skill[1]) // required pick lock skill applying
2973 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2975 SendCastResult(SPELL_FAILED_FIZZLE);
2976 return;
2979 reqSkillValue = lockInfo->Skill[1];
2981 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2983 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2984 return;
2987 if ( SkillId )
2989 loottype = LOOT_SKINNING;
2990 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2992 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2993 return;
2996 // update skill if really known
2997 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2998 if(SkillValue) // non only item base skill
3000 if(gameObjTarget)
3002 // Allow one skill-up until respawned
3003 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3004 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
3005 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3007 else if(itemTarget)
3009 // Do one skill-up
3010 uint32 SkillValue = player->GetPureSkillValue(SkillId);
3011 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
3016 SendLoot(guid, loottype);
3019 void Spell::EffectSummonChangeItem(uint32 i)
3021 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3022 return;
3024 Player *player = (Player*)m_caster;
3026 // applied only to using item
3027 if(!m_CastItem)
3028 return;
3030 // ... only to item in own inventory/bank/equip_slot
3031 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3032 return;
3034 uint32 newitemid = m_spellInfo->EffectItemType[i];
3035 if(!newitemid)
3036 return;
3038 uint16 pos = m_CastItem->GetPos();
3040 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3041 if( !pNewItem )
3042 return;
3044 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3046 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3047 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3050 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3052 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3053 player->DurabilityLoss(pNewItem, loosePercent);
3056 if( player->IsInventoryPos( pos ) )
3058 ItemPosCountVec dest;
3059 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3060 if( msg == EQUIP_ERR_OK )
3062 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3064 // prevent crash at access and unexpected charges counting with item update queue corrupt
3065 if(m_CastItem==m_targets.getItemTarget())
3066 m_targets.setItemTarget(NULL);
3068 m_CastItem = NULL;
3070 player->StoreItem( dest, pNewItem, true);
3071 return;
3074 else if( player->IsBankPos ( pos ) )
3076 ItemPosCountVec dest;
3077 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3078 if( msg == EQUIP_ERR_OK )
3080 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3082 // prevent crash at access and unexpected charges counting with item update queue corrupt
3083 if(m_CastItem==m_targets.getItemTarget())
3084 m_targets.setItemTarget(NULL);
3086 m_CastItem = NULL;
3088 player->BankItem( dest, pNewItem, true);
3089 return;
3092 else if( player->IsEquipmentPos ( pos ) )
3094 uint16 dest;
3095 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3096 if( msg == EQUIP_ERR_OK )
3098 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3100 // prevent crash at access and unexpected charges counting with item update queue corrupt
3101 if(m_CastItem==m_targets.getItemTarget())
3102 m_targets.setItemTarget(NULL);
3104 m_CastItem = NULL;
3106 player->EquipItem( dest, pNewItem, true);
3107 player->AutoUnequipOffhandIfNeed();
3108 return;
3112 // fail
3113 delete pNewItem;
3116 void Spell::EffectOpenSecretSafe(uint32 i)
3118 EffectOpenLock(i); //no difference for now
3121 void Spell::EffectProficiency(uint32 /*i*/)
3123 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3124 return;
3125 Player *p_target = (Player*)unitTarget;
3127 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3128 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3130 p_target->AddWeaponProficiency(subClassMask);
3131 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3133 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3135 p_target->AddArmorProficiency(subClassMask);
3136 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3140 void Spell::EffectApplyAreaAura(uint32 i)
3142 if(!unitTarget)
3143 return;
3144 if(!unitTarget->isAlive())
3145 return;
3147 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3148 unitTarget->AddAura(Aur);
3151 void Spell::EffectSummonType(uint32 i)
3153 switch(m_spellInfo->EffectMiscValueB[i])
3155 case SUMMON_TYPE_GUARDIAN:
3156 case SUMMON_TYPE_POSESSED:
3157 case SUMMON_TYPE_POSESSED2:
3158 case SUMMON_TYPE_GUARDIAN2:
3159 EffectSummonGuardian(i);
3160 break;
3161 case SUMMON_TYPE_WILD:
3162 EffectSummonWild(i);
3163 break;
3164 case SUMMON_TYPE_DEMON:
3165 EffectSummonDemon(i);
3166 break;
3167 case SUMMON_TYPE_SUMMON:
3168 EffectSummon(i);
3169 break;
3170 case SUMMON_TYPE_CRITTER:
3171 case SUMMON_TYPE_CRITTER2:
3172 case SUMMON_TYPE_CRITTER3:
3173 EffectSummonCritter(i);
3174 break;
3175 case SUMMON_TYPE_TOTEM_SLOT1:
3176 case SUMMON_TYPE_TOTEM_SLOT2:
3177 case SUMMON_TYPE_TOTEM_SLOT3:
3178 case SUMMON_TYPE_TOTEM_SLOT4:
3179 case SUMMON_TYPE_TOTEM:
3180 EffectSummonTotem(i);
3181 break;
3182 case SUMMON_TYPE_UNKNOWN1:
3183 case SUMMON_TYPE_UNKNOWN2:
3184 case SUMMON_TYPE_UNKNOWN3:
3185 case SUMMON_TYPE_UNKNOWN4:
3186 case SUMMON_TYPE_UNKNOWN5:
3187 break;
3188 default:
3189 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3190 break;
3194 void Spell::EffectSummon(uint32 i)
3196 if(m_caster->GetPetGUID())
3197 return;
3199 if(!unitTarget)
3200 return;
3201 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3202 if(!pet_entry)
3203 return;
3204 uint32 level = m_caster->getLevel();
3205 Pet* spawnCreature = new Pet(SUMMON_PET);
3207 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3209 // set timer for unsummon
3210 int32 duration = GetSpellDuration(m_spellInfo);
3211 if(duration > 0)
3212 spawnCreature->SetDuration(duration);
3214 return;
3217 Map *map = m_caster->GetMap();
3218 uint32 pet_number = objmgr.GeneratePetNumber();
3219 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3221 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3222 delete spawnCreature;
3223 return;
3226 // Summon in dest location
3227 float x,y,z;
3228 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3230 x = m_targets.m_destX;
3231 y = m_targets.m_destY;
3232 z = m_targets.m_destZ;
3234 else
3235 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3237 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3239 if(!spawnCreature->IsPositionValid())
3241 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3242 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3243 delete spawnCreature;
3244 return;
3247 // set timer for unsummon
3248 int32 duration = GetSpellDuration(m_spellInfo);
3249 if(duration > 0)
3250 spawnCreature->SetDuration(duration);
3252 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3253 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3254 spawnCreature->setPowerType(POWER_MANA);
3255 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3256 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3257 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3258 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3259 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3260 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3261 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3262 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3263 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3265 spawnCreature->InitStatsForLevel(level);
3267 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3269 spawnCreature->AIM_Initialize();
3270 spawnCreature->InitPetCreateSpells();
3271 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3272 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3274 std::string name = m_caster->GetName();
3275 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3276 spawnCreature->SetName( name );
3278 map->Add((Creature*)spawnCreature);
3280 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3282 m_caster->SetPet(spawnCreature);
3283 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3284 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3285 ((Player*)m_caster)->PetSpellInitialize();
3289 void Spell::EffectLearnSpell(uint32 i)
3291 if(!unitTarget)
3292 return;
3294 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3296 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3297 EffectLearnPetSpell(i);
3299 return;
3302 Player *player = (Player*)unitTarget;
3304 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3305 player->learnSpell(spellToLearn);
3307 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3310 void Spell::EffectDispel(uint32 i)
3312 if(!unitTarget)
3313 return;
3315 // Fill possible dispell list
3316 std::vector <Aura *> dispel_list;
3318 // Create dispel mask by dispel type
3319 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3320 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3321 Unit::AuraMap const& auras = unitTarget->GetAuras();
3322 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3324 Aura *aur = (*itr).second;
3325 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3327 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3329 bool positive = true;
3330 if (!aur->IsPositive())
3331 positive = false;
3332 else
3333 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3335 // do not remove positive auras if friendly target
3336 // negative auras if non-friendly target
3337 if(positive == unitTarget->IsFriendlyTo(m_caster))
3338 continue;
3340 // Add aura to dispel list
3341 dispel_list.push_back(aur);
3344 // Ok if exist some buffs for dispel try dispel it
3345 if (!dispel_list.empty())
3347 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3348 std::list < uint32 > fail_list; // spell_id
3349 int32 list_size = dispel_list.size();
3350 // Dispell N = damage buffs (or while exist buffs for dispel)
3351 for (int32 count=0; count < damage && list_size > 0; ++count)
3353 // Random select buff for dispel
3354 Aura *aur = dispel_list[urand(0, list_size-1)];
3356 SpellEntry const* spellInfo = aur->GetSpellProto();
3357 // Base dispel chance
3358 // TODO: possible chance depend from spell level??
3359 int32 miss_chance = 0;
3360 // Apply dispel mod from aura caster
3361 if (Unit *caster = aur->GetCaster())
3363 if ( Player* modOwner = caster->GetSpellModOwner() )
3364 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3366 // Try dispel
3367 if (roll_chance_i(miss_chance))
3368 fail_list.push_back(aur->GetId());
3369 else
3370 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3371 // Remove buff from list for prevent doubles
3372 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3374 Aura *dispeled = *j;
3375 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3377 j = dispel_list.erase(j);
3378 --list_size;
3380 else
3381 ++j;
3384 // Send success log and really remove auras
3385 if (!success_list.empty())
3387 int32 count = success_list.size();
3388 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3389 data.append(unitTarget->GetPackGUID()); // Victim GUID
3390 data.append(m_caster->GetPackGUID()); // Caster GUID
3391 data << uint32(m_spellInfo->Id); // Dispell spell id
3392 data << uint8(0); // not used
3393 data << uint32(count); // count
3394 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3396 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3397 data << uint32(spellInfo->Id); // Spell Id
3398 data << uint8(0); // 0 - dispeled !=0 cleansed
3399 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3401 m_caster->SendMessageToSet(&data, true);
3403 // On succes dispel
3404 // Devour Magic
3405 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3407 uint32 heal_spell = 0;
3408 switch (m_spellInfo->Id)
3410 case 19505: heal_spell = 19658; break;
3411 case 19731: heal_spell = 19732; break;
3412 case 19734: heal_spell = 19733; break;
3413 case 19736: heal_spell = 19735; break;
3414 case 27276: heal_spell = 27278; break;
3415 case 27277: heal_spell = 27279; break;
3416 default:
3417 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3418 break;
3420 if (heal_spell)
3421 m_caster->CastSpell(m_caster, heal_spell, true);
3424 // Send fail log to client
3425 if (!fail_list.empty())
3427 // Failed to dispell
3428 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3429 data << uint64(m_caster->GetGUID()); // Caster GUID
3430 data << uint64(unitTarget->GetGUID()); // Victim GUID
3431 data << uint32(m_spellInfo->Id); // Dispell spell id
3432 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3433 data << uint32(*j); // Spell Id
3434 m_caster->SendMessageToSet(&data, true);
3439 void Spell::EffectDualWield(uint32 /*i*/)
3441 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3442 ((Player*)unitTarget)->SetCanDualWield(true);
3445 void Spell::EffectPull(uint32 /*i*/)
3447 // TODO: create a proper pull towards distract spell center for distract
3448 sLog.outDebug("WORLD: Spell Effect DUMMY");
3451 void Spell::EffectDistract(uint32 /*i*/)
3453 // Check for possible target
3454 if (!unitTarget || unitTarget->isInCombat())
3455 return;
3457 // target must be OK to do this
3458 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3459 return;
3461 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3463 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3465 // For players just turn them
3466 WorldPacket data;
3467 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3468 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3469 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3471 else
3473 // Set creature Distracted, Stop it, And turn it
3474 unitTarget->SetOrientation(angle);
3475 unitTarget->StopMoving();
3476 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3480 void Spell::EffectPickPocket(uint32 /*i*/)
3482 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3483 return;
3485 // victim must be creature and attackable
3486 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3487 return;
3489 // victim have to be alive and humanoid or undead
3490 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3492 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3494 if (chance > irand(0, 19))
3496 // Stealing successful
3497 //sLog.outDebug("Sending loot from pickpocket");
3498 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3500 else
3502 // Reveal action + get attack
3503 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3504 if (((Creature*)unitTarget)->AI())
3505 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3510 void Spell::EffectAddFarsight(uint32 i)
3512 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3513 int32 duration = GetSpellDuration(m_spellInfo);
3514 DynamicObject* dynObj = new DynamicObject;
3515 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))
3517 delete dynObj;
3518 return;
3520 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3521 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3522 m_caster->AddDynObject(dynObj);
3523 dynObj->GetMap()->Add(dynObj);
3524 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3525 ((Player*)m_caster)->SetFarSight(dynObj->GetGUID());
3528 void Spell::EffectSummonWild(uint32 i)
3530 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3531 if(!creature_entry)
3532 return;
3534 uint32 level = m_caster->getLevel();
3536 // level of creature summoned using engineering item based at engineering skill level
3537 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3539 ItemPrototype const *proto = m_CastItem->GetProto();
3540 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3542 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3543 if(skill202)
3545 level = skill202/5;
3550 // select center of summon position
3551 float center_x = m_targets.m_destX;
3552 float center_y = m_targets.m_destY;
3553 float center_z = m_targets.m_destZ;
3555 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3557 int32 amount = damage > 0 ? damage : 1;
3559 for(int32 count = 0; count < amount; ++count)
3561 float px, py, pz;
3562 // If dest location if present
3563 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3565 // Summon 1 unit in dest location
3566 if (count == 0)
3568 px = m_targets.m_destX;
3569 py = m_targets.m_destY;
3570 pz = m_targets.m_destZ;
3572 // Summon in random point all other units if location present
3573 else
3574 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3576 // Summon if dest location not present near caster
3577 else
3578 m_caster->GetClosePoint(px,py,pz,3.0f);
3580 int32 duration = GetSpellDuration(m_spellInfo);
3582 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3584 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3588 void Spell::EffectSummonGuardian(uint32 i)
3590 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3591 if(!pet_entry)
3592 return;
3594 // Jewelery statue case (totem like)
3595 if(m_spellInfo->SpellIconID==2056)
3597 EffectSummonTotem(i);
3598 return;
3601 // set timer for unsummon
3602 int32 duration = GetSpellDuration(m_spellInfo);
3604 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3605 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3606 // so this code hack in fact
3607 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3608 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3609 return; // find old guardian, ignore summon
3611 // in another case summon new
3612 uint32 level = m_caster->getLevel();
3614 // level of pet summoned using engineering item based at engineering skill level
3615 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3617 ItemPrototype const *proto = m_CastItem->GetProto();
3618 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3620 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3621 if(skill202)
3623 level = skill202/5;
3628 // select center of summon position
3629 float center_x = m_targets.m_destX;
3630 float center_y = m_targets.m_destY;
3631 float center_z = m_targets.m_destZ;
3633 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3635 int32 amount = damage > 0 ? damage : 1;
3637 for(int32 count = 0; count < amount; ++count)
3639 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3641 Map *map = m_caster->GetMap();
3642 uint32 pet_number = objmgr.GeneratePetNumber();
3643 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3645 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3646 delete spawnCreature;
3647 return;
3650 float px, py, pz;
3651 // If dest location if present
3652 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3654 // Summon 1 unit in dest location
3655 if (count == 0)
3657 px = m_targets.m_destX;
3658 py = m_targets.m_destY;
3659 pz = m_targets.m_destZ;
3661 // Summon in random point all other units if location present
3662 else
3663 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3665 // Summon if dest location not present near caster
3666 else
3667 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3669 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3671 if(!spawnCreature->IsPositionValid())
3673 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3674 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3675 delete spawnCreature;
3676 return;
3679 if(duration > 0)
3680 spawnCreature->SetDuration(duration);
3682 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3683 spawnCreature->setPowerType(POWER_MANA);
3684 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3685 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3686 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3687 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3688 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3689 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3690 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3692 spawnCreature->InitStatsForLevel(level);
3693 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3695 spawnCreature->AIM_Initialize();
3697 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3698 ((Player*)m_caster)->AddGuardian(spawnCreature);
3700 map->Add((Creature*)spawnCreature);
3704 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3706 if(!unitTarget)
3707 return;
3709 if(unitTarget->isInFlight())
3710 return;
3712 uint32 mapid = m_caster->GetMapId();
3713 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3715 float fx,fy,fz;
3716 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3718 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3719 ((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));
3720 else
3721 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3724 void Spell::EffectLearnSkill(uint32 i)
3726 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3727 return;
3729 if(damage < 0)
3730 return;
3732 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3733 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3734 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3737 void Spell::EffectAddHonor(uint32 /*i*/)
3739 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3740 return;
3742 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3744 // TODO: find formula for honor reward based on player's level!
3746 // now fixed only for level 70 players:
3747 if (((Player*)unitTarget)->getLevel() == 70)
3748 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3751 void Spell::EffectTradeSkill(uint32 /*i*/)
3753 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3754 return;
3755 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3756 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3757 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3760 void Spell::EffectEnchantItemPerm(uint32 i)
3762 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3763 return;
3764 if (!itemTarget)
3765 return;
3767 Player* p_caster = (Player*)m_caster;
3769 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3771 if (m_spellInfo->EffectMiscValue[i])
3773 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3775 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3776 if(!pEnchant)
3777 return;
3779 // item can be in trade slot and have owner diff. from caster
3780 Player* item_owner = itemTarget->GetOwner();
3781 if(!item_owner)
3782 return;
3784 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3786 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3787 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3788 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3789 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3792 // remove old enchanting before applying new if equipped
3793 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3795 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3797 // add new enchanting if equipped
3798 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3802 void Spell::EffectEnchantItemTmp(uint32 i)
3804 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3805 return;
3807 Player* p_caster = (Player*)m_caster;
3809 if(!itemTarget)
3810 return;
3812 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3814 // Shaman Rockbiter Weapon
3815 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3817 int32 enchnting_damage = m_currentBasePoints[1]+1;
3819 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3820 // with already applied percent bonus from Elemental Weapons talent
3821 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3822 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3823 switch(enchnting_damage)
3825 // Rank 1
3826 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3827 // Rank 2
3828 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3829 case 5: enchant_id = 3025; break; // 20%
3830 // Rank 3
3831 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3832 case 7: enchant_id = 3027; break; // 20%
3833 // Rank 4
3834 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3835 case 10: enchant_id = 503; break; // 14%
3836 case 11: enchant_id = 3031; break; // 20%
3837 // Rank 5
3838 case 15: enchant_id = 3035; break; // 0%
3839 case 16: enchant_id = 1663; break; // 7%
3840 case 17: enchant_id = 3033; break; // 14%
3841 case 18: enchant_id = 3034; break; // 20%
3842 // Rank 6
3843 case 28: enchant_id = 3038; break; // 0%
3844 case 29: enchant_id = 683; break; // 7%
3845 case 31: enchant_id = 3036; break; // 14%
3846 case 33: enchant_id = 3037; break; // 20%
3847 // Rank 7
3848 case 40: enchant_id = 3041; break; // 0%
3849 case 42: enchant_id = 1664; break; // 7%
3850 case 45: enchant_id = 3039; break; // 14%
3851 case 48: enchant_id = 3040; break; // 20%
3852 // Rank 8
3853 case 49: enchant_id = 3044; break; // 0%
3854 case 52: enchant_id = 2632; break; // 7%
3855 case 55: enchant_id = 3042; break; // 14%
3856 case 58: enchant_id = 3043; break; // 20%
3857 // Rank 9
3858 case 62: enchant_id = 2633; break; // 0%
3859 case 66: enchant_id = 3018; break; // 7%
3860 case 70: enchant_id = 3019; break; // 14%
3861 case 74: enchant_id = 3020; break; // 20%
3862 default:
3863 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3864 return;
3868 if (!enchant_id)
3870 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3871 return;
3874 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3875 if(!pEnchant)
3877 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3878 return;
3881 // select enchantment duration
3882 uint32 duration;
3884 // rogue family enchantments exception by duration
3885 if(m_spellInfo->Id==38615)
3886 duration = 1800; // 30 mins
3887 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3888 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3889 duration = 3600; // 1 hour
3890 // shaman family enchantments
3891 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3892 duration = 1800; // 30 mins
3893 // other cases with this SpellVisual already selected
3894 else if(m_spellInfo->SpellVisual[0]==215)
3895 duration = 1800; // 30 mins
3896 // some fishing pole bonuses
3897 else if(m_spellInfo->SpellVisual[0]==563)
3898 duration = 600; // 10 mins
3899 // shaman rockbiter enchantments
3900 else if(m_spellInfo->SpellVisual[0]==0)
3901 duration = 1800; // 30 mins
3902 else if(m_spellInfo->Id==29702)
3903 duration = 300; // 5 mins
3904 else if(m_spellInfo->Id==37360)
3905 duration = 300; // 5 mins
3906 // default case
3907 else
3908 duration = 3600; // 1 hour
3910 // item can be in trade slot and have owner diff. from caster
3911 Player* item_owner = itemTarget->GetOwner();
3912 if(!item_owner)
3913 return;
3915 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3917 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3918 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3919 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3920 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3923 // remove old enchanting before applying new if equipped
3924 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3926 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3928 // add new enchanting if equipped
3929 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3932 void Spell::EffectTameCreature(uint32 /*i*/)
3934 if(m_caster->GetPetGUID())
3935 return;
3937 if(!unitTarget)
3938 return;
3940 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3941 return;
3943 Creature* creatureTarget = (Creature*)unitTarget;
3945 if(creatureTarget->isPet())
3946 return;
3948 if(m_caster->getClass() != CLASS_HUNTER)
3949 return;
3951 // cast finish successfully
3952 //SendChannelUpdate(0);
3953 finish();
3955 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3957 // kill original creature
3958 creatureTarget->setDeathState(JUST_DIED);
3959 creatureTarget->RemoveCorpse();
3960 creatureTarget->SetHealth(0); // just for nice GM-mode view
3962 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
3964 // prepare visual effect for levelup
3965 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
3967 // add to world
3968 pet->GetMap()->Add((Creature*)pet);
3970 // visual effect for levelup
3971 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
3973 // caster have pet now
3974 m_caster->SetPet(pet);
3976 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3978 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3979 ((Player*)m_caster)->PetSpellInitialize();
3983 void Spell::EffectSummonPet(uint32 i)
3985 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3987 Pet *OldSummon = m_caster->GetPet();
3989 // if pet requested type already exist
3990 if( OldSummon )
3992 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3994 // pet in corpse state can't be summoned
3995 if( OldSummon->isDead() )
3996 return;
3998 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
3999 OldSummon->SetMapId(m_caster->GetMapId());
4001 float px, py, pz;
4002 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4004 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4005 m_caster->GetMap()->Add((Creature*)OldSummon);
4007 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4009 ((Player*)m_caster)->PetSpellInitialize();
4011 return;
4014 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4015 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4016 else
4017 return;
4020 Pet* NewSummon = new Pet;
4022 // petentry==0 for hunter "call pet" (current pet summoned if any)
4023 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4025 if(NewSummon->getPetType()==SUMMON_PET)
4027 // Remove Demonic Sacrifice auras (known pet)
4028 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4029 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4031 if((*itr)->GetModifier()->m_miscvalue==2228)
4033 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4034 itr = auraClassScripts.begin();
4036 else
4037 ++itr;
4041 return;
4044 // not error in case fail hunter call pet
4045 if(!petentry)
4047 delete NewSummon;
4048 return;
4051 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4053 if(!cInfo)
4055 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4056 delete NewSummon;
4057 return;
4060 Map *map = m_caster->GetMap();
4061 uint32 pet_number = objmgr.GeneratePetNumber();
4062 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4064 delete NewSummon;
4065 return;
4068 float px, py, pz;
4069 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4071 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4073 if(!NewSummon->IsPositionValid())
4075 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4076 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4077 delete NewSummon;
4078 return;
4081 uint32 petlevel = m_caster->getLevel();
4082 NewSummon->setPetType(SUMMON_PET);
4084 uint32 faction = m_caster->getFaction();
4085 if(m_caster->GetTypeId() == TYPEID_UNIT)
4087 if ( ((Creature*)m_caster)->isTotem() )
4088 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4089 else
4090 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4093 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4094 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4095 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4096 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4097 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4098 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4099 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4100 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4101 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4102 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4104 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4105 // this enables pet details window (Shift+P)
4107 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4108 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4109 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4111 NewSummon->InitStatsForLevel(petlevel);
4112 NewSummon->InitPetCreateSpells();
4114 if(NewSummon->getPetType()==SUMMON_PET)
4116 // Remove Demonic Sacrifice auras (new pet)
4117 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4118 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4120 if((*itr)->GetModifier()->m_miscvalue==2228)
4122 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4123 itr = auraClassScripts.begin();
4125 else
4126 ++itr;
4129 // generate new name for summon pet
4130 std::string new_name=objmgr.GeneratePetName(petentry);
4131 if(!new_name.empty())
4132 NewSummon->SetName(new_name);
4134 else if(NewSummon->getPetType()==HUNTER_PET)
4135 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4137 NewSummon->AIM_Initialize();
4138 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4139 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4141 map->Add((Creature*)NewSummon);
4143 m_caster->SetPet(NewSummon);
4144 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4146 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4148 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4149 ((Player*)m_caster)->PetSpellInitialize();
4153 void Spell::EffectLearnPetSpell(uint32 i)
4155 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4156 return;
4158 Player *_player = (Player*)m_caster;
4160 Pet *pet = _player->GetPet();
4161 if(!pet)
4162 return;
4163 if(!pet->isAlive())
4164 return;
4166 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4167 if(!learn_spellproto)
4168 return;
4170 pet->learnSpell(learn_spellproto->Id);
4172 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4173 _player->PetSpellInitialize();
4176 void Spell::EffectTaunt(uint32 /*i*/)
4178 // this effect use before aura Taunt apply for prevent taunt already attacking target
4179 // for spell as marked "non effective at already attacking target"
4180 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4182 if(unitTarget->getVictim()==m_caster)
4184 SendCastResult(SPELL_FAILED_DONT_REPORT);
4185 return;
4189 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4190 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4191 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4194 void Spell::EffectWeaponDmg(uint32 i)
4196 if(!unitTarget)
4197 return;
4198 if(!unitTarget->isAlive())
4199 return;
4201 // multiple weapon dmg effect workaround
4202 // execute only the last weapon damage
4203 // and handle all effects at once
4204 for (int j = 0; j < 3; j++)
4206 switch(m_spellInfo->Effect[j])
4208 case SPELL_EFFECT_WEAPON_DAMAGE:
4209 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4210 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4211 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4212 if (j < i) // we must calculate only at last weapon effect
4213 return;
4214 break;
4218 // some spell specific modifiers
4219 bool customBonusDamagePercentMod = false;
4220 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4221 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4222 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4223 bool normalized = false;
4225 int32 spell_bonus = 0; // bonus specific for spell
4226 switch(m_spellInfo->SpellFamilyName)
4228 case SPELLFAMILY_WARRIOR:
4230 // Whirlwind, single only spell with 2 weapon white damage apply if have
4231 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4233 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4234 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4236 // Devastate bonus and sunder armor refresh
4237 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4239 customBonusDamagePercentMod = true;
4240 bonusDamagePercentMod = 0.0f; // only applied if auras found
4242 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4243 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4245 SpellEntry const *proto = (*itr)->GetSpellProto();
4246 if(proto->SpellVisual[0] == 406 && proto->SpellIconID == 565)
4248 int32 duration = GetSpellDuration(proto);
4249 (*itr)->SetAuraDuration(duration);
4250 (*itr)->SendAuraUpdate(false);
4251 bonusDamagePercentMod += 1.0f; // +100%
4255 break;
4257 case SPELLFAMILY_ROGUE:
4259 // Ambush
4260 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4262 customBonusDamagePercentMod = true;
4263 bonusDamagePercentMod = 2.5f; // 250%
4265 // Mutilate (for each hand)
4266 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4268 bool found = false;
4269 // fast check
4270 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4271 found = true;
4272 // full aura scan
4273 else
4275 Unit::AuraMap const& auras = unitTarget->GetAuras();
4276 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4278 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4280 found = true;
4281 break;
4286 if(found)
4287 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4289 break;
4291 case SPELLFAMILY_PALADIN:
4293 // Seal of Command - receive benefit from Spell Damage and Healing
4294 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4296 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4297 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4299 break;
4301 case SPELLFAMILY_SHAMAN:
4303 // Skyshatter Harness item set bonus
4304 // Stormstrike
4305 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4307 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4308 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4310 // Stormstrike AP Buff
4311 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4313 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4314 break;
4321 int32 fixed_bonus = 0;
4322 for (int j = 0; j < 3; j++)
4324 switch(m_spellInfo->Effect[j])
4326 case SPELL_EFFECT_WEAPON_DAMAGE:
4327 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4328 fixed_bonus += CalculateDamage(j,unitTarget);
4329 break;
4330 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4331 fixed_bonus += CalculateDamage(j,unitTarget);
4332 normalized = true;
4333 break;
4334 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4335 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4337 // applied only to prev.effects fixed damage
4338 if(customBonusDamagePercentMod)
4339 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4340 else
4341 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4342 break;
4343 default:
4344 break; // not weapon damage effect, just skip
4348 // non-weapon damage
4349 int32 bonus = spell_bonus + fixed_bonus;
4351 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4352 if(bonus)
4354 UnitMods unitMod;
4355 switch(m_attackType)
4357 default:
4358 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4359 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4360 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4363 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4364 bonus = int32(bonus*weapon_total_pct);
4367 // + weapon damage with applied weapon% dmg to base weapon damage in call
4368 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4370 // total damage
4371 bonus = int32(bonus*totalDamagePercentMod);
4373 // prevent negative damage
4374 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4376 // Add melee damage bonuses (also check for negative)
4377 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4378 m_damage+= eff_damage;
4380 // Hemorrhage
4381 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4383 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4384 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4387 // Mangle (Cat): CP
4388 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4390 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4391 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4394 // take ammo
4395 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4397 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4399 // wands don't have ammo
4400 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4401 return;
4403 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4405 if(pItem->GetMaxStackCount()==1)
4407 // decrease durability for non-stackable throw weapon
4408 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4410 else
4412 // decrease items amount for stackable throw weapon
4413 uint32 count = 1;
4414 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4417 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4418 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4422 void Spell::EffectThreat(uint32 /*i*/)
4424 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4425 return;
4427 if(!unitTarget->CanHaveThreatList())
4428 return;
4430 unitTarget->AddThreat(m_caster, float(damage));
4433 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4435 if(!unitTarget)
4436 return;
4437 if(!unitTarget->isAlive())
4438 return;
4440 uint32 heal = m_caster->GetMaxHealth();
4442 m_healing+=heal;
4445 void Spell::EffectInterruptCast(uint32 /*i*/)
4447 if(!unitTarget)
4448 return;
4449 if(!unitTarget->isAlive())
4450 return;
4452 // TODO: not all spells that used this effect apply cooldown at school spells
4453 // also exist case: apply cooldown to interrupted cast only and to all spells
4454 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4456 if (unitTarget->m_currentSpells[i])
4458 // check if we can interrupt spell
4459 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4461 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4462 unitTarget->InterruptSpell(i,false);
4468 void Spell::EffectSummonObjectWild(uint32 i)
4470 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4472 GameObject* pGameObj = new GameObject;
4474 WorldObject* target = focusObject;
4475 if( !target )
4476 target = m_caster;
4478 float x,y,z;
4479 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4481 x = m_targets.m_destX;
4482 y = m_targets.m_destY;
4483 z = m_targets.m_destZ;
4485 else
4486 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4488 Map *map = target->GetMap();
4490 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4491 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4493 delete pGameObj;
4494 return;
4497 int32 duration = GetSpellDuration(m_spellInfo);
4498 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4499 pGameObj->SetSpellId(m_spellInfo->Id);
4501 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4502 m_caster->AddGameObject(pGameObj);
4503 map->Add(pGameObj);
4505 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4507 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4509 Player *pl = (Player*)m_caster;
4510 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4511 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4513 uint32 team = ALLIANCE;
4515 if(pl->GetTeam() == team)
4516 team = HORDE;
4518 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4523 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4525 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4527 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4528 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4530 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4535 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4537 GameObject* linkedGO = new GameObject;
4538 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4539 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4541 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4542 linkedGO->SetSpellId(m_spellInfo->Id);
4544 m_caster->AddGameObject(linkedGO);
4545 map->Add(linkedGO);
4547 else
4549 delete linkedGO;
4550 linkedGO = NULL;
4551 return;
4556 void Spell::EffectScriptEffect(uint32 effIndex)
4558 // TODO: we must implement hunter pet summon at login there (spell 6962)
4560 // by spell id
4561 switch(m_spellInfo->Id)
4563 // PX-238 Winter Wondervolt TRAP
4564 case 26275:
4566 if( unitTarget->HasAura(26272,0)
4567 || unitTarget->HasAura(26157,0)
4568 || unitTarget->HasAura(26273,0)
4569 || unitTarget->HasAura(26274,0))
4570 return;
4572 uint32 iTmpSpellId;
4574 switch(urand(0,3))
4576 case 0:
4577 iTmpSpellId = 26272;
4578 break;
4579 case 1:
4580 iTmpSpellId = 26157;
4581 break;
4582 case 2:
4583 iTmpSpellId = 26273;
4584 break;
4585 case 3:
4586 iTmpSpellId = 26274;
4587 break;
4590 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4592 return;
4595 // Bending Shinbone
4596 case 8856:
4598 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4599 return;
4601 uint32 spell_id = 0;
4602 switch(urand(1,5))
4604 case 1: spell_id = 8854; break;
4605 default: spell_id = 8855; break;
4608 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4609 return;
4612 // Healthstone creating spells
4613 case 6201:
4614 case 6202:
4615 case 5699:
4616 case 11729:
4617 case 11730:
4618 case 27230:
4620 uint32 itemtype;
4621 uint32 rank = 0;
4622 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4623 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4625 if((*i)->GetId() == 18692)
4627 rank = 1;
4628 break;
4630 else if((*i)->GetId() == 18693)
4632 rank = 2;
4633 break;
4637 static uint32 const itypes[6][3] = {
4638 { 5512,19004,19005}, // Minor Healthstone
4639 { 5511,19006,19007}, // Lesser Healthstone
4640 { 5509,19008,19009}, // Healthstone
4641 { 5510,19010,19011}, // Greater Healthstone
4642 { 9421,19012,19013}, // Major Healthstone
4643 {22103,22104,22105} // Master Healthstone
4646 switch(m_spellInfo->Id)
4648 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4649 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4650 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4651 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4652 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4653 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4654 default:
4655 return;
4657 DoCreateItem( effIndex, itemtype );
4658 return;
4660 // Brittle Armor - need remove one 24575 Brittle Armor aura
4661 case 24590:
4662 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4663 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4664 return;
4665 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4666 case 26465:
4667 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4668 return;
4669 // Orb teleport spells
4670 case 25140:
4671 case 25143:
4672 case 25650:
4673 case 25652:
4674 case 29128:
4675 case 29129:
4676 case 35376:
4677 case 35727:
4679 if(!unitTarget)
4680 return;
4682 uint32 spellid;
4683 switch(m_spellInfo->Id)
4685 case 25140: spellid = 32571; break;
4686 case 25143: spellid = 32572; break;
4687 case 25650: spellid = 30140; break;
4688 case 25652: spellid = 30141; break;
4689 case 29128: spellid = 32568; break;
4690 case 29129: spellid = 32569; break;
4691 case 35376: spellid = 25649; break;
4692 case 35727: spellid = 35730; break;
4693 default:
4694 return;
4697 unitTarget->CastSpell(unitTarget,spellid,false);
4698 return;
4701 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4702 case 22539:
4703 case 22972:
4704 case 22975:
4705 case 22976:
4706 case 22977:
4707 case 22978:
4708 case 22979:
4709 case 22980:
4710 case 22981:
4711 case 22982:
4712 case 22983:
4713 case 22984:
4714 case 22985:
4716 if(!unitTarget || !unitTarget->isAlive())
4717 return;
4719 // Onyxia Scale Cloak
4720 if(unitTarget->GetDummyAura(22683))
4721 return;
4723 // Shadow Flame
4724 m_caster->CastSpell(unitTarget, 22682, true);
4725 return;
4727 break;
4729 // Summon Black Qiraji Battle Tank
4730 case 26656:
4732 if(!unitTarget)
4733 return;
4735 // Prevent stacking of mounts
4736 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4738 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4739 if (unitTarget->GetAreaId() == 3428)
4740 unitTarget->CastSpell(unitTarget, 25863, false);
4741 else
4742 unitTarget->CastSpell(unitTarget, 26655, false);
4743 break;
4745 // Piccolo of the Flaming Fire
4746 case 17512:
4748 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4749 return;
4750 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4751 break;
4754 // Dreaming Glory
4755 case 28698:
4757 if(!unitTarget)
4758 return;
4759 unitTarget->CastSpell(unitTarget, 28694, true);
4760 break;
4763 // Netherbloom
4764 case 28702:
4766 if(!unitTarget)
4767 return;
4768 // 25% chance of casting a random buff
4769 if(roll_chance_i(75))
4770 return;
4772 // triggered spells are 28703 to 28707
4773 // Note: some sources say, that there was the possibility of
4774 // receiving a debuff. However, this seems to be removed by a patch.
4775 const uint32 spellid = 28703;
4777 // don't overwrite an existing aura
4778 for(uint8 i=0; i<5; i++)
4779 if(unitTarget->HasAura(spellid+i, 0))
4780 return;
4781 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4782 break;
4785 // Nightmare Vine
4786 case 28720:
4788 if(!unitTarget)
4789 return;
4790 // 25% chance of casting Nightmare Pollen
4791 if(roll_chance_i(75))
4792 return;
4793 unitTarget->CastSpell(unitTarget, 28721, true);
4794 break;
4797 // Mirren's Drinking Hat
4798 case 29830:
4800 uint32 item = 0;
4801 switch ( urand(1,6) )
4803 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4804 case 4: case 5: item = 23585; break;// Stouthammer Lite
4805 case 6: item = 23586; break;// Aerie Peak Pale Ale
4807 if (item)
4808 DoCreateItem(effIndex,item);
4809 break;
4811 // Improved Sprint
4812 case 30918:
4814 // Removes snares and roots.
4815 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4816 Unit::AuraMap& Auras = unitTarget->GetAuras();
4817 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4819 next = iter;
4820 ++next;
4821 Aura *aur = iter->second;
4822 if (!aur->IsPositive()) //only remove negative spells
4824 // check for mechanic mask
4825 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4827 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4828 if(Auras.empty())
4829 break;
4830 else
4831 next = Auras.begin();
4835 break;
4837 case 41126: // Flame Crash
4839 if(!unitTarget)
4840 return;
4842 unitTarget->CastSpell(unitTarget, 41131, true);
4843 break;
4845 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4847 if(!unitTarget)
4848 return;
4850 unitTarget->CastSpell(unitTarget, 44870, true);
4851 break;
4854 // Goblin Weather Machine
4855 case 46203:
4857 if(!unitTarget)
4858 return;
4860 uint32 spellId;
4861 switch(rand()%4)
4863 case 0:
4864 spellId=46740;
4865 break;
4866 case 1:
4867 spellId=46739;
4868 break;
4869 case 2:
4870 spellId=46738;
4871 break;
4872 case 3:
4873 spellId=46736;
4874 break;
4876 unitTarget->CastSpell(unitTarget, spellId, true);
4877 break;
4879 //5,000 Gold
4880 case 46642:
4882 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4883 return;
4885 ((Player*)unitTarget)->ModifyMoney(50000000);
4887 break;
4889 case 51770:
4891 if(!unitTarget)
4892 return;
4894 unitTarget->CastSpell(unitTarget,51771,false);
4895 break;
4898 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER )
4900 switch(m_spellInfo->Id)
4902 // Chimera Shot
4903 case 53209:
4905 uint32 spellId = 0;
4906 int32 basePoint = 0;
4907 Unit::AuraMap& Auras = unitTarget->GetAuras();
4908 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
4910 Aura *aura = (*i).second;
4911 if (aura->GetCasterGUID() != m_caster->GetGUID())
4912 continue;
4913 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
4914 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
4915 if (!(familyFlag & 0x000000800000C000LL))
4916 continue;
4917 // Refresh aura duration
4918 aura->SetAuraDuration(aura->GetAuraMaxDuration());
4919 aura->SendAuraUpdate(false);
4921 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
4922 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
4924 spellId = 53353; // 53353 Chimera Shot - Serpent
4925 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
4927 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
4928 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
4930 spellId = 53358; // 53358 Chimera Shot - Viper
4931 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
4933 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
4934 if (familyFlag & 0x0000000000008000LL)
4935 spellId = 53359; // 53359 Chimera Shot - Scorpid
4936 // ?? nothing say in spell desc (possibly need addition check)
4937 //if (familyFlag & 0x0000010000000000LL || // dot
4938 // familyFlag & 0x0000100000000000LL) // stun
4940 // spellId = 53366; // 53366 Chimera Shot - Wyvern
4943 if (spellId)
4944 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
4945 return;
4947 default:
4948 break;
4951 else if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4953 switch(m_spellInfo->SpellFamilyFlags)
4955 // Judgement
4956 case 0x800000:
4958 if(!unitTarget || !unitTarget->isAlive())
4959 return;
4960 uint32 spellId2 = 0;
4962 // all seals have aura dummy
4963 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4964 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4966 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4968 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4969 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4970 continue;
4972 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4973 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4975 if(spellId2 <= 1)
4976 continue;
4978 // found, remove seal
4979 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4981 // Sanctified Judgement
4982 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4983 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4985 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4987 int32 chance = (*i)->GetModifier()->m_amount;
4988 if ( roll_chance_i(chance) )
4990 int32 mana = spellInfo->manaCost;
4991 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4992 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4993 mana = int32(mana* 0.8f);
4994 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4996 break;
5000 break;
5003 m_caster->CastSpell(unitTarget,spellId2,true);
5004 return;
5009 // normal DB scripted effect
5010 if(!unitTarget)
5011 return;
5013 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5014 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5017 void Spell::EffectSanctuary(uint32 /*i*/)
5019 if(!unitTarget)
5020 return;
5021 //unitTarget->CombatStop();
5023 unitTarget->CombatStop();
5024 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5025 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5026 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5028 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5032 void Spell::EffectAddComboPoints(uint32 /*i*/)
5034 if(!unitTarget)
5035 return;
5037 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5038 return;
5040 if(damage <= 0)
5041 return;
5043 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5046 void Spell::EffectDuel(uint32 i)
5048 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5049 return;
5051 Player *caster = (Player*)m_caster;
5052 Player *target = (Player*)unitTarget;
5054 // caster or target already have requested duel
5055 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5056 return;
5058 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5059 // Don't have to check the target's map since you cannot challenge someone across maps
5060 uint32 mapid = caster->GetMapId();
5061 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5063 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5064 return;
5067 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5068 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5070 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5071 return;
5074 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5075 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5077 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5078 return;
5081 //CREATE DUEL FLAG OBJECT
5082 GameObject* pGameObj = new GameObject;
5084 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5086 Map *map = m_caster->GetMap();
5087 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
5088 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5089 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5090 m_caster->GetPositionZ(),
5091 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
5093 delete pGameObj;
5094 return;
5097 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5098 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5099 int32 duration = GetSpellDuration(m_spellInfo);
5100 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5101 pGameObj->SetSpellId(m_spellInfo->Id);
5103 m_caster->AddGameObject(pGameObj);
5104 map->Add(pGameObj);
5105 //END
5107 // Send request
5108 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5109 data << pGameObj->GetGUID();
5110 data << caster->GetGUID();
5111 caster->GetSession()->SendPacket(&data);
5112 target->GetSession()->SendPacket(&data);
5114 // create duel-info
5115 DuelInfo *duel = new DuelInfo;
5116 duel->initiator = caster;
5117 duel->opponent = target;
5118 duel->startTime = 0;
5119 duel->startTimer = 0;
5120 caster->duel = duel;
5122 DuelInfo *duel2 = new DuelInfo;
5123 duel2->initiator = caster;
5124 duel2->opponent = caster;
5125 duel2->startTime = 0;
5126 duel2->startTimer = 0;
5127 target->duel = duel2;
5129 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5130 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5133 void Spell::EffectStuck(uint32 /*i*/)
5135 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5136 return;
5138 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5139 return;
5141 Player* pTarget = (Player*)unitTarget;
5143 sLog.outDebug("Spell Effect: Stuck");
5144 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());
5146 if(pTarget->isInFlight())
5147 return;
5149 // homebind location is loaded always
5150 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5152 // Stuck spell trigger Hearthstone cooldown
5153 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5154 if(!spellInfo)
5155 return;
5156 Spell spell(pTarget,spellInfo,true,0);
5157 spell.SendSpellCooldown();
5160 void Spell::EffectSummonPlayer(uint32 /*i*/)
5162 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5163 return;
5165 // Evil Twin (ignore player summon, but hide this for summoner)
5166 if(unitTarget->GetDummyAura(23445))
5167 return;
5169 float x,y,z;
5170 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5172 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5174 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5175 data << uint64(m_caster->GetGUID()); // summoner guid
5176 data << uint32(m_caster->GetZoneId()); // summoner zone
5177 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5178 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5181 static ScriptInfo generateActivateCommand()
5183 ScriptInfo si;
5184 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5185 return si;
5188 void Spell::EffectActivateObject(uint32 effect_idx)
5190 if(!gameObjTarget)
5191 return;
5193 static ScriptInfo activateCommand = generateActivateCommand();
5195 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5197 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5200 void Spell::EffectApplyGlyph(uint32 i)
5202 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5203 return;
5205 Player *player = (Player*)m_caster;
5207 // remove old glyph
5208 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5210 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5212 player->RemoveAurasDueToSpell(old_gp->SpellId);
5213 player->SetGlyph(m_glyphIndex, 0);
5217 // apply new one
5218 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5220 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5222 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5224 if(gp->TypeFlags != gs->TypeFlags)
5226 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5227 return; // glyph slot missmatch
5231 player->CastSpell(m_caster, gp->SpellId, true);
5232 player->SetGlyph(m_glyphIndex, glyph);
5237 void Spell::EffectSummonTotem(uint32 i)
5239 uint8 slot = 0;
5240 switch(m_spellInfo->EffectMiscValueB[i])
5242 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5243 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5244 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5245 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5246 // Battle standard case
5247 case SUMMON_TYPE_TOTEM: slot = 254; break;
5248 // jewelery statue case, like totem without slot
5249 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5250 default: return;
5253 if(slot < MAX_TOTEM)
5255 uint64 guid = m_caster->m_TotemSlot[slot];
5256 if(guid != 0)
5258 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5259 if(OldTotem && OldTotem->isTotem())
5260 ((Totem*)OldTotem)->UnSummon();
5264 uint32 team = 0;
5265 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5266 team = ((Player*)m_caster)->GetTeam();
5268 Totem* pTotem = new Totem;
5270 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5272 delete pTotem;
5273 return;
5276 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5278 float x,y,z;
5279 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5281 // totem must be at same Z in case swimming caster and etc.
5282 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5283 z = m_caster->GetPositionZ();
5285 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5287 if(slot < MAX_TOTEM)
5288 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5290 pTotem->SetOwner(m_caster->GetGUID());
5291 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5293 int32 duration=GetSpellDuration(m_spellInfo);
5294 if(Player* modOwner = m_caster->GetSpellModOwner())
5295 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5296 pTotem->SetDuration(duration);
5298 if (damage) // if not spell info, DB values used
5300 pTotem->SetMaxHealth(damage);
5301 pTotem->SetHealth(damage);
5304 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5306 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5307 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5309 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5310 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5312 pTotem->Summon(m_caster);
5314 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5316 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5317 data << uint8(slot);
5318 data << uint64(pTotem->GetGUID());
5319 data << uint32(duration);
5320 data << uint32(m_spellInfo->Id);
5321 ((Player*)m_caster)->SendDirectMessage(&data);
5325 void Spell::EffectEnchantHeldItem(uint32 i)
5327 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5328 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5329 return;
5331 Player* item_owner = (Player*)unitTarget;
5332 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5334 if(!item )
5335 return;
5337 // must be equipped
5338 if(!item ->IsEquipped())
5339 return;
5341 if (m_spellInfo->EffectMiscValue[i])
5343 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5344 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5345 if(!duration)
5346 duration = m_currentBasePoints[i]+1; //Base points after ..
5347 if(!duration)
5348 duration = 10; //10 seconds for enchants which don't have listed duration
5350 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5351 if(!pEnchant)
5352 return;
5354 // Always go to temp enchantment slot
5355 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5357 // Enchantment will not be applied if a different one already exists
5358 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5359 return;
5361 // Apply the temporary enchantment
5362 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5363 item_owner->ApplyEnchantment(item,slot,true);
5367 void Spell::EffectDisEnchant(uint32 /*i*/)
5369 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5370 return;
5372 Player* p_caster = (Player*)m_caster;
5373 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5374 return;
5376 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5378 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5380 // item will be removed at disenchanting end
5383 void Spell::EffectInebriate(uint32 /*i*/)
5385 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5386 return;
5388 Player *player = (Player*)unitTarget;
5389 uint16 currentDrunk = player->GetDrunkValue();
5390 uint16 drunkMod = damage * 256;
5391 if (currentDrunk + drunkMod > 0xFFFF)
5392 currentDrunk = 0xFFFF;
5393 else
5394 currentDrunk += drunkMod;
5395 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5398 void Spell::EffectFeedPet(uint32 i)
5400 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5401 return;
5403 Player *_player = (Player*)m_caster;
5405 Item* foodItem = m_targets.getItemTarget();
5406 if(!foodItem)
5407 return;
5409 Pet *pet = _player->GetPet();
5410 if(!pet)
5411 return;
5413 if(!pet->isAlive())
5414 return;
5416 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5417 if(benefit <= 0)
5418 return;
5420 uint32 count = 1;
5421 _player->DestroyItemCount(foodItem,count,true);
5422 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5424 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5427 void Spell::EffectDismissPet(uint32 /*i*/)
5429 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5430 return;
5432 Pet* pet = m_caster->GetPet();
5434 // not let dismiss dead pet
5435 if(!pet||!pet->isAlive())
5436 return;
5438 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5441 void Spell::EffectSummonObject(uint32 i)
5443 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5445 uint8 slot = 0;
5446 switch(m_spellInfo->Effect[i])
5448 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5449 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5450 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5451 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5452 default: return;
5455 uint64 guid = m_caster->m_ObjectSlot[slot];
5456 if(guid != 0)
5458 GameObject* obj = NULL;
5459 if( m_caster )
5460 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5462 if(obj) obj->Delete();
5463 m_caster->m_ObjectSlot[slot] = 0;
5466 GameObject* pGameObj = new GameObject;
5468 float rot2 = sin(m_caster->GetOrientation()/2);
5469 float rot3 = cos(m_caster->GetOrientation()/2);
5471 float x,y,z;
5472 // If dest location if present
5473 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5475 x = m_targets.m_destX;
5476 y = m_targets.m_destY;
5477 z = m_targets.m_destZ;
5479 // Summon in random point all other units if location present
5480 else
5481 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5483 Map *map = m_caster->GetMap();
5484 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5486 delete pGameObj;
5487 return;
5490 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5491 int32 duration = GetSpellDuration(m_spellInfo);
5492 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5493 pGameObj->SetSpellId(m_spellInfo->Id);
5494 m_caster->AddGameObject(pGameObj);
5496 map->Add(pGameObj);
5497 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5498 data << pGameObj->GetGUID();
5499 m_caster->SendMessageToSet(&data,true);
5501 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5504 void Spell::EffectResurrect(uint32 /*effIndex*/)
5506 if(!unitTarget)
5507 return;
5508 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5509 return;
5511 if(unitTarget->isAlive())
5512 return;
5513 if(!unitTarget->IsInWorld())
5514 return;
5516 switch (m_spellInfo->Id)
5518 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5519 case 8342:
5520 if (roll_chance_i(67))
5522 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5523 return;
5525 break;
5526 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5527 case 22999:
5528 if (roll_chance_i(50))
5530 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5531 return;
5533 break;
5534 default:
5535 break;
5538 Player* pTarget = ((Player*)unitTarget);
5540 if(pTarget->isRessurectRequested()) // already have one active request
5541 return;
5543 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5544 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5546 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5547 SendResurrectRequest(pTarget);
5550 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5552 if(!unitTarget || !unitTarget->isAlive())
5553 return;
5555 if( unitTarget->m_extraAttacks )
5556 return;
5558 unitTarget->m_extraAttacks = damage;
5561 void Spell::EffectParry(uint32 /*i*/)
5563 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5564 ((Player*)unitTarget)->SetCanParry(true);
5567 void Spell::EffectBlock(uint32 /*i*/)
5569 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5570 ((Player*)unitTarget)->SetCanBlock(true);
5573 void Spell::EffectMomentMove(uint32 i)
5575 if(unitTarget->isInFlight())
5576 return;
5578 if( m_spellInfo->rangeIndex== 1) //self range
5580 uint32 mapid = m_caster->GetMapId();
5581 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5583 // before caster
5584 float fx,fy,fz;
5585 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5586 float ox,oy,oz;
5587 unitTarget->GetPosition(ox,oy,oz);
5589 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5590 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5592 fx = fx2;
5593 fy = fy2;
5594 fz = fz2;
5595 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5598 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5599 ((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));
5600 else
5601 m_caster->GetMap()->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5605 void Spell::EffectReputation(uint32 i)
5607 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5608 return;
5610 Player *_player = (Player*)unitTarget;
5612 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5614 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5616 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5618 if(!factionEntry)
5619 return;
5621 _player->ModifyFactionReputation(factionEntry,rep_change);
5624 void Spell::EffectQuestComplete(uint32 i)
5626 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5627 return;
5629 Player *_player = (Player*)m_caster;
5631 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5632 _player->AreaExploredOrEventHappens(quest_id);
5635 void Spell::EffectSelfResurrect(uint32 i)
5637 if(!unitTarget || unitTarget->isAlive())
5638 return;
5639 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5640 return;
5641 if(!unitTarget->IsInWorld())
5642 return;
5644 uint32 health = 0;
5645 uint32 mana = 0;
5647 // flat case
5648 if(damage < 0)
5650 health = uint32(-damage);
5651 mana = m_spellInfo->EffectMiscValue[i];
5653 // percent case
5654 else
5656 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5657 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5658 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5661 Player *plr = ((Player*)unitTarget);
5662 plr->ResurrectPlayer(0.0f);
5664 plr->SetHealth( health );
5665 plr->SetPower(POWER_MANA, mana );
5666 plr->SetPower(POWER_RAGE, 0 );
5667 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5669 plr->SpawnCorpseBones();
5671 plr->SaveToDB();
5674 void Spell::EffectSkinning(uint32 /*i*/)
5676 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5677 return;
5678 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5679 return;
5681 Creature* creature = (Creature*) unitTarget;
5682 int32 targetLevel = creature->getLevel();
5684 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5686 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5687 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5689 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5691 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5693 // Double chances for elites
5694 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5697 void Spell::EffectCharge(uint32 /*i*/)
5699 if(!unitTarget || !m_caster)
5700 return;
5702 float x, y, z;
5703 unitTarget->GetContactPoint(m_caster, x, y, z);
5704 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5705 ((Creature *)unitTarget)->StopMoving();
5707 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5708 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5710 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5711 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5713 // not all charge effects used in negative spells
5714 if ( !IsPositiveSpell(m_spellInfo->Id))
5715 m_caster->Attack(unitTarget,true);
5718 void Spell::EffectSummonCritter(uint32 i)
5720 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5721 return;
5722 Player* player = (Player*)m_caster;
5724 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5725 if(!pet_entry)
5726 return;
5728 Pet* old_critter = player->GetMiniPet();
5730 // for same pet just despawn
5731 if(old_critter && old_critter->GetEntry() == pet_entry)
5733 player->RemoveMiniPet();
5734 return;
5737 // despawn old pet before summon new
5738 if(old_critter)
5739 player->RemoveMiniPet();
5741 // summon new pet
5742 Pet* critter = new Pet(MINI_PET);
5744 Map *map = m_caster->GetMap();
5745 uint32 pet_number = objmgr.GeneratePetNumber();
5746 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5747 map, pet_entry, pet_number))
5749 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5750 delete critter;
5751 return;
5754 float x,y,z;
5755 // If dest location if present
5756 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5758 x = m_targets.m_destX;
5759 y = m_targets.m_destY;
5760 z = m_targets.m_destZ;
5762 // Summon if dest location not present near caster
5763 else
5764 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5766 critter->Relocate(x,y,z,m_caster->GetOrientation());
5768 if(!critter->IsPositionValid())
5770 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5771 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5772 delete critter;
5773 return;
5776 critter->SetOwnerGUID(m_caster->GetGUID());
5777 critter->SetCreatorGUID(m_caster->GetGUID());
5778 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5779 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5781 critter->AIM_Initialize();
5782 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5783 critter->SetMaxHealth(1);
5784 critter->SetHealth(1);
5785 critter->SetLevel(1);
5787 // set timer for unsummon
5788 int32 duration = GetSpellDuration(m_spellInfo);
5789 if(duration > 0)
5790 critter->SetDuration(duration);
5792 std::string name = player->GetName();
5793 name.append(petTypeSuffix[critter->getPetType()]);
5794 critter->SetName( name );
5795 player->SetMiniPet(critter);
5797 map->Add((Creature*)critter);
5800 void Spell::EffectKnockBack(uint32 i)
5802 if(!unitTarget || !m_caster)
5803 return;
5805 // Effect only works on players
5806 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5807 return;
5809 float vsin = sin(m_caster->GetAngle(unitTarget));
5810 float vcos = cos(m_caster->GetAngle(unitTarget));
5812 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5813 data.append(unitTarget->GetPackGUID());
5814 data << uint32(0); // Sequence
5815 data << float(vcos); // x direction
5816 data << float(vsin); // y direction
5817 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5818 data << float(damage/-10); // Z Movement speed (vertical)
5820 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5823 void Spell::EffectSendTaxi(uint32 i)
5825 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5826 return;
5828 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5829 if(!entry)
5830 return;
5832 std::vector<uint32> nodes;
5834 nodes.resize(2);
5835 nodes[0] = entry->from;
5836 nodes[1] = entry->to;
5838 uint32 mountid = 0;
5839 switch(m_spellInfo->Id)
5841 case 31606: //Stormcrow Amulet
5842 mountid = 17447;
5843 break;
5844 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5845 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5846 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5847 mountid = 22840;
5848 break;
5849 case 34905: //Stealth Flight
5850 mountid = 6851;
5851 break;
5852 case 53335: //Stormwind Harbor Flight - Peaceful
5853 mountid = 6852;
5854 break;
5857 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5861 void Spell::EffectPlayerPull(uint32 i)
5863 if(!unitTarget || !m_caster)
5864 return;
5866 // Effect only works on players
5867 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5868 return;
5870 float vsin = sin(unitTarget->GetAngle(m_caster));
5871 float vcos = cos(unitTarget->GetAngle(m_caster));
5873 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5874 data.append(unitTarget->GetPackGUID());
5875 data << uint32(0); // Sequence
5876 data << float(vcos); // x direction
5877 data << float(vsin); // y direction
5878 // Horizontal speed
5879 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5880 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5882 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5885 void Spell::EffectDispelMechanic(uint32 i)
5887 if(!unitTarget)
5888 return;
5890 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5892 Unit::AuraMap& Auras = unitTarget->GetAuras();
5893 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5895 next = iter;
5896 ++next;
5897 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5898 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5900 unitTarget->RemoveAurasDueToSpell(spell->Id);
5901 if(Auras.empty())
5902 break;
5903 else
5904 next = Auras.begin();
5907 return;
5910 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5912 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5913 return;
5914 Player *_player = (Player*)m_caster;
5915 Pet *pet = _player->GetPet();
5916 if(!pet)
5917 return;
5918 if(pet->isAlive())
5919 return;
5920 if(damage < 0)
5921 return;
5922 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5923 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5924 pet->setDeathState( ALIVE );
5925 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5926 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5928 pet->AIM_Initialize();
5930 _player->PetSpellInitialize();
5931 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5934 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5936 float mana = 0;
5937 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5939 if(!m_caster->m_TotemSlot[slot])
5940 continue;
5942 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5943 if(totem && totem->isTotem())
5945 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5946 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5947 if(spellInfo)
5948 mana += spellInfo->manaCost * damage / 100;
5949 ((Totem*)totem)->UnSummon();
5953 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5954 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5957 void Spell::EffectDurabilityDamage(uint32 i)
5959 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5960 return;
5962 int32 slot = m_spellInfo->EffectMiscValue[i];
5964 // FIXME: some spells effects have value -1/-2
5965 // Possibly its mean -1 all player equipped items and -2 all items
5966 if(slot < 0)
5968 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5969 return;
5972 // invalid slot value
5973 if(slot >= INVENTORY_SLOT_BAG_END)
5974 return;
5976 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5977 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5980 void Spell::EffectDurabilityDamagePCT(uint32 i)
5982 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5983 return;
5985 int32 slot = m_spellInfo->EffectMiscValue[i];
5987 // FIXME: some spells effects have value -1/-2
5988 // Possibly its mean -1 all player equipped items and -2 all items
5989 if(slot < 0)
5991 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5992 return;
5995 // invalid slot value
5996 if(slot >= INVENTORY_SLOT_BAG_END)
5997 return;
5999 if(damage <= 0)
6000 return;
6002 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6003 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6006 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6008 if(!unitTarget)
6009 return;
6011 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6014 void Spell::EffectTransmitted(uint32 effIndex)
6016 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6018 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6020 if (!goinfo)
6022 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6023 return;
6026 float fx,fy,fz;
6028 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6030 fx = m_targets.m_destX;
6031 fy = m_targets.m_destY;
6032 fz = m_targets.m_destZ;
6034 //FIXME: this can be better check for most objects but still hack
6035 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6037 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6038 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6040 else
6042 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6043 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6044 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6046 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6049 Map *cMap = m_caster->GetMap();
6051 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6053 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6054 { // but this is not proper, we really need to ignore not materialized objects
6055 SendCastResult(SPELL_FAILED_NOT_HERE);
6056 SendChannelUpdate(0);
6057 return;
6060 // replace by water level in this case
6061 fz = cMap->GetWaterLevel(fx,fy);
6063 // if gameobject is summoning object, it should be spawned right on caster's position
6064 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6066 m_caster->GetPosition(fx,fy,fz);
6069 GameObject* pGameObj = new GameObject;
6071 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6072 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6074 delete pGameObj;
6075 return;
6078 int32 duration = GetSpellDuration(m_spellInfo);
6080 switch(goinfo->type)
6082 case GAMEOBJECT_TYPE_FISHINGNODE:
6084 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6085 // Orientation3
6086 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, 0.88431775569915771 );
6087 // Orientation4
6088 pGameObj->SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, -0.4668855369091033 );
6089 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6091 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6092 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6093 int32 lastSec;
6094 switch(urand(0, 3))
6096 case 0: lastSec = 3; break;
6097 case 1: lastSec = 7; break;
6098 case 2: lastSec = 13; break;
6099 case 3: lastSec = 17; break;
6102 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
6103 break;
6105 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6107 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6109 pGameObj->AddUniqueUse((Player*)m_caster);
6110 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6112 break;
6114 case GAMEOBJECT_TYPE_FISHINGHOLE:
6115 case GAMEOBJECT_TYPE_CHEST:
6116 default:
6118 break;
6122 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6124 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6126 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6127 pGameObj->SetSpellId(m_spellInfo->Id);
6129 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
6130 //m_caster->AddGameObject(pGameObj);
6131 //m_ObjToDel.push_back(pGameObj);
6133 cMap->Add(pGameObj);
6135 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6136 data << uint64(pGameObj->GetGUID());
6137 m_caster->SendMessageToSet(&data,true);
6139 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6141 GameObject* linkedGO = new GameObject;
6142 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6143 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
6145 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
6146 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6147 linkedGO->SetSpellId(m_spellInfo->Id);
6148 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6150 linkedGO->GetMap()->Add(linkedGO);
6152 else
6154 delete linkedGO;
6155 linkedGO = NULL;
6156 return;
6161 void Spell::EffectProspecting(uint32 /*i*/)
6163 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6164 return;
6166 Player* p_caster = (Player*)m_caster;
6167 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6168 return;
6170 if(itemTarget->GetCount() < 5)
6171 return;
6173 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6175 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6176 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6177 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6180 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6183 void Spell::EffectMilling(uint32 /*i*/)
6185 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6186 return;
6188 Player* p_caster = (Player*)m_caster;
6189 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6190 return;
6192 if(itemTarget->GetCount() < 5)
6193 return;
6195 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6197 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6198 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6199 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6202 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6205 void Spell::EffectSkill(uint32 /*i*/)
6207 sLog.outDebug("WORLD: SkillEFFECT");
6210 void Spell::EffectSummonDemon(uint32 i)
6212 float px = m_targets.m_destX;
6213 float py = m_targets.m_destY;
6214 float pz = m_targets.m_destZ;
6216 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6217 if (!Charmed)
6218 return;
6220 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6221 Charmed->SetLevel(m_caster->getLevel());
6223 // TODO: Add damage/mana/hp according to level
6225 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6227 // Enslave demon effect, without mana cost and cooldown
6228 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6230 // Inferno effect
6231 Charmed->CastSpell(Charmed, 22703, true, 0);
6235 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6236 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6237 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6238 This is why we use a half sec delay between the visual effect and the resurrection itself */
6239 void Spell::EffectSpiritHeal(uint32 /*i*/)
6242 if(!unitTarget || unitTarget->isAlive())
6243 return;
6244 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6245 return;
6246 if(!unitTarget->IsInWorld())
6247 return;
6249 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6250 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6251 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6252 ((Player*)unitTarget)->SpawnCorpseBones();
6256 // remove insignia spell effect
6257 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6259 sLog.outDebug("Effect: SkinPlayerCorpse");
6260 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6261 return;
6263 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6266 void Spell::EffectStealBeneficialBuff(uint32 i)
6268 sLog.outDebug("Effect: StealBeneficialBuff");
6270 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6271 return;
6273 std::vector <Aura *> steal_list;
6274 // Create dispel mask by dispel type
6275 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6276 Unit::AuraMap const& auras = unitTarget->GetAuras();
6277 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6279 Aura *aur = (*itr).second;
6280 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6282 // Need check for passive? this
6283 if (aur->IsPositive() && !aur->IsPassive())
6284 steal_list.push_back(aur);
6287 // Ok if exist some buffs for dispel try dispel it
6288 if (!steal_list.empty())
6290 std::list < std::pair<uint32,uint64> > success_list;
6291 int32 list_size = steal_list.size();
6292 // Dispell N = damage buffs (or while exist buffs for dispel)
6293 for (int32 count=0; count < damage && list_size > 0; ++count)
6295 // Random select buff for dispel
6296 Aura *aur = steal_list[urand(0, list_size-1)];
6297 // Not use chance for steal
6298 // TODO possible need do it
6299 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6301 // Remove buff from list for prevent doubles
6302 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6304 Aura *stealed = *j;
6305 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6307 j = steal_list.erase(j);
6308 --list_size;
6310 else
6311 ++j;
6314 // Really try steal and send log
6315 if (!success_list.empty())
6317 int32 count = success_list.size();
6318 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6319 data.append(unitTarget->GetPackGUID()); // Victim GUID
6320 data.append(m_caster->GetPackGUID()); // Caster GUID
6321 data << uint32(m_spellInfo->Id); // Dispell spell id
6322 data << uint8(0); // not used
6323 data << uint32(count); // count
6324 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6326 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6327 data << uint32(spellInfo->Id); // Spell Id
6328 data << uint8(0); // 0 - steals !=0 transfers
6329 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6331 m_caster->SendMessageToSet(&data, true);
6336 void Spell::EffectKillCredit(uint32 i)
6338 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6339 return;
6341 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6344 void Spell::EffectQuestFail(uint32 i)
6346 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6347 return;
6349 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6352 void Spell::EffectActivateRune(uint32 i)
6354 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6355 return;
6357 Player *plr = (Player*)m_caster;
6359 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6360 return;
6362 for(uint32 j = 0; j < MAX_RUNES; ++j)
6364 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[i])
6366 plr->SetRuneCooldown(j, 0);
6371 void Spell::EffectTitanGrip(uint32 i)
6373 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6374 ((Player*)unitTarget)->SetCanTitanGrip(true);