[7668] Cleanup In CreatureAI function descriptions and AttackStart/AttackedBy use.
[AHbot.git] / src / game / SpellEffects.cpp
blob74ed51043f08960775113362a2b2a8a36a709b8f
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 "Database/DatabaseEnv.h"
21 #include "WorldPacket.h"
22 #include "Opcodes.h"
23 #include "Log.h"
24 #include "UpdateMask.h"
25 #include "World.h"
26 #include "ObjectMgr.h"
27 #include "SpellMgr.h"
28 #include "Player.h"
29 #include "SkillExtraItems.h"
30 #include "Unit.h"
31 #include "Spell.h"
32 #include "DynamicObject.h"
33 #include "SpellAuras.h"
34 #include "Group.h"
35 #include "UpdateData.h"
36 #include "MapManager.h"
37 #include "ObjectAccessor.h"
38 #include "SharedDefines.h"
39 #include "Pet.h"
40 #include "GameObject.h"
41 #include "GossipDef.h"
42 #include "Creature.h"
43 #include "Totem.h"
44 #include "CreatureAI.h"
45 #include "BattleGroundMgr.h"
46 #include "BattleGround.h"
47 #include "BattleGroundEY.h"
48 #include "BattleGroundWS.h"
49 #include "VMapFactory.h"
50 #include "Language.h"
51 #include "SocialMgr.h"
52 #include "Util.h"
53 #include "TemporarySummon.h"
54 #include "ScriptCalls.h"
55 #include "SkillDiscovery.h"
56 #include "Formulas.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::EffectUnused, // 41 SPELL_EFFECT_JUMP
102 &Spell::EffectJump, // 42 SPELL_EFFECT_JUMP2
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::EffectUnused, // 97 SPELL_EFFECT_97
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::EffectUnused, //112 SPELL_EFFECT_112
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::EffectEnchantItemPrismatic, //156 SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
217 &Spell::EffectCreateItem2, //157 SPELL_EFFECT_CREATE_ITEM_2 create/learn item/spell for profession
218 &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling
219 &Spell::EffectRenamePet //159 SPELL_EFFECT_ALLOW_RENAME_PET 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->CalculateSimpleValue(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(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 & 0x0000020000000000LL && m_spellInfo->Category==1209)
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 // Shockwave ${$m3/100*$AP}
388 else if(m_spellInfo->SpellFamilyFlags & 0x0000800000000000LL)
390 int32 pct = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
391 if (pct > 0)
392 damage+= int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * pct / 100);
393 break;
395 break;
397 case SPELLFAMILY_WARLOCK:
399 // Incinerate Rank 1 & 2
400 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
402 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
403 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
404 damage += int32(damage*0.25f);
406 break;
408 case SPELLFAMILY_PRIEST:
410 // Shadow Word: Death - deals damage equal to damage done to caster
411 if (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL)
412 m_caster->CastCustomSpell(m_caster, 32409, &damage, 0, 0, true);
413 break;
415 case SPELLFAMILY_DRUID:
417 // Ferocious Bite
418 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual[0]==6587)
420 // converts each extra point of energy into ($f1+$AP/410) additional damage
421 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
422 float multiple = ap / 410 + m_spellInfo->DmgMultiplier[effect_idx];
423 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
424 damage += int32(((Player*)m_caster)->GetComboPoints() * ap * 7 / 100);
425 m_caster->SetPower(POWER_ENERGY,0);
427 // Rake
428 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
430 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
432 // Swipe
433 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
435 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
437 //Mangle Bonus for the initial damage of Lacerate and Rake
438 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
439 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
441 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
442 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
443 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
445 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
446 break;
449 break;
451 case SPELLFAMILY_ROGUE:
453 // Envenom
454 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
456 // consume from stack dozes not more that have combo-points
457 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
459 Aura *poison = 0;
460 // Lookup for Deadly poison (only attacker applied)
461 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
462 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
463 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE &&
464 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000 &&
465 (*itr)->GetCasterGUID()==m_caster->GetGUID() )
467 poison = *itr;
468 break;
470 // count consumed deadly poison doses at target
471 if (poison)
473 uint32 spellId = poison->GetId();
474 uint32 doses = poison->GetStackAmount();
475 if (doses > combo)
476 doses = combo;
477 for (int i=0; i< doses; i++)
478 unitTarget->RemoveSingleSpellAurasFromStack(spellId);
479 damage *= doses;
480 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
482 // Eviscerate and Envenom Bonus Damage (item set effect)
483 if(m_caster->GetDummyAura(37169))
484 damage += ((Player*)m_caster)->GetComboPoints()*40;
487 // Eviscerate
488 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
490 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
492 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
493 damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f));
495 // Eviscerate and Envenom Bonus Damage (item set effect)
496 if(m_caster->GetDummyAura(37169))
497 damage += combo*40;
500 // Gouge
501 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000000008LL)
503 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.02f);
505 // Instant Poison
506 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
508 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.10f);
510 // Wound Poison
511 else if(m_spellInfo->SpellFamilyFlags & 0x0000000010000000LL)
513 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.04f);
515 break;
517 case SPELLFAMILY_HUNTER:
519 // Mongoose Bite
520 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual[0]==342)
522 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
524 // Counterattack
525 else if(m_spellInfo->SpellFamilyFlags & 0x0008000000000000LL)
527 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
529 // Arcane Shot
530 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
532 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15f);
534 // Steady Shot
535 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
537 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
538 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
540 // Explosive Trap Effect
541 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
543 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1f);
545 break;
547 case SPELLFAMILY_PALADIN:
549 // Judgement of Vengeance ${1+0.22*$SPH+0.14*$AP} + 10% for each application of Holy Vengeance on the target
550 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
552 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
553 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
554 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
555 damage+=int32(ap * 0.14f) + int32(holy * 22 / 100);
556 // Get stack of Holy Vengeance on the target added by caster
557 uint32 stacks = 0;
558 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
559 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
560 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
562 stacks = (*itr)->GetStackAmount();
563 break;
565 // + 10% for each application of Holy Vengeance on the target
566 if(stacks)
567 damage += damage * stacks * 10 /100;
569 // Avenger's Shield ($m1+0.07*$SPH+0.07*$AP) - ranged sdb for future
570 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
572 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
573 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
574 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
575 damage += int32(ap * 0.07f) + int32(holy * 7 / 100);
577 // Hammer of Wrath ($m1+0.15*$SPH+0.15*$AP) - ranged type sdb future fix
578 else if(m_spellInfo->SpellFamilyFlags & 0x0000008000000000LL)
580 float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
581 int32 holy = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)) +
582 m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget);
583 damage += int32(ap * 0.15f) + int32(holy * 15 / 100);
585 // Hammer of the Righteous
586 else if(m_spellInfo->SpellFamilyFlags&0x0004000000000000LL)
588 // Add main hand dps * effect[2] amount
589 float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
590 int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
591 damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
593 // Shield of Righteousness
594 else if(m_spellInfo->SpellFamilyFlags&0x0010000000000000LL)
596 damage+=int32(m_caster->GetShieldBlockValue());
598 break;
602 if(damage >= 0)
603 m_damage+= damage;
607 void Spell::EffectDummy(uint32 i)
609 if(!unitTarget && !gameObjTarget && !itemTarget)
610 return;
612 // selection by spell family
613 switch(m_spellInfo->SpellFamilyName)
615 case SPELLFAMILY_GENERIC:
617 switch(m_spellInfo->Id )
619 case 8063: // Deviate Fish
621 if(m_caster->GetTypeId() != TYPEID_PLAYER)
622 return;
624 uint32 spell_id = 0;
625 switch(urand(1,5))
627 case 1: spell_id = 8064; break; // Sleepy
628 case 2: spell_id = 8065; break; // Invigorate
629 case 3: spell_id = 8066; break; // Shrink
630 case 4: spell_id = 8067; break; // Party Time!
631 case 5: spell_id = 8068; break; // Healthy Spirit
633 m_caster->CastSpell(m_caster,spell_id,true,NULL);
634 return;
636 case 8213: // Savory Deviate Delight
638 if(m_caster->GetTypeId() != TYPEID_PLAYER)
639 return;
641 uint32 spell_id = 0;
642 switch(urand(1,2))
644 // Flip Out - ninja
645 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
646 // Yaaarrrr - pirate
647 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
649 m_caster->CastSpell(m_caster,spell_id,true,NULL);
650 return;
652 case 8593: // Symbol of life (restore creature to life)
653 case 31225: // Shimmering Vessel (restore creature to life)
655 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
656 return;
657 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
658 return;
660 case 12162: // Deep wounds
661 case 12850: // (now good common check for this spells)
662 case 12868:
664 if(!unitTarget)
665 return;
667 float damage;
668 // DW should benefit of attack power, damage percent mods etc.
669 // TODO: check if using offhand damage is correct and if it should be divided by 2
670 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
671 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
672 else
673 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
675 switch (m_spellInfo->Id)
677 case 12850: damage *= 0.2f; break;
678 case 12162: damage *= 0.4f; break;
679 case 12868: damage *= 0.6f; break;
680 default:
681 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
682 return;
685 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
686 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
687 return;
689 case 13120: // net-o-matic
691 if(!unitTarget)
692 return;
694 uint32 spell_id = 0;
696 uint32 roll = urand(0, 99);
698 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
699 spell_id = 16566;
700 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
701 spell_id = 13119;
702 else // normal root
703 spell_id = 13099;
705 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
706 return;
708 case 13567: // Dummy Trigger
710 // can be used for different aura triggering, so select by aura
711 if(!m_triggeredByAuraSpell || !unitTarget)
712 return;
714 switch(m_triggeredByAuraSpell->Id)
716 case 26467: // Persistent Shield
717 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
718 break;
719 default:
720 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
721 break;
723 return;
725 case 15998: // Capture Worg Pup
726 case 29435: // Capture Female Kaliri Hatchling
728 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
729 return;
731 Creature* creatureTarget = (Creature*)unitTarget;
732 creatureTarget->setDeathState(JUST_DIED);
733 creatureTarget->RemoveCorpse();
734 creatureTarget->SetHealth(0); // just for nice GM-mode view
735 return;
737 case 16589: // Noggenfogger Elixir
739 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
740 return;
742 uint32 spell_id = 0;
743 switch(urand(1,3))
745 case 1: spell_id = 16595; break;
746 case 2: spell_id = 16593; break;
747 default:spell_id = 16591; break;
750 m_caster->CastSpell(m_caster,spell_id,true,NULL);
751 return;
753 case 17251: // Spirit Healer Res
755 if(!unitTarget || !m_originalCaster)
756 return;
758 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
760 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
761 data << unitTarget->GetGUID();
762 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
764 return;
766 case 17271: // Test Fetid Skull
768 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
769 return;
771 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
773 m_caster->CastSpell(m_caster,spell_id,true,NULL);
774 return;
776 case 20577: // Cannibalize
777 if (unitTarget)
778 m_caster->CastSpell(m_caster,20578,false,NULL);
779 return;
780 case 23019: // Crystal Prison Dummy DND
782 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
783 return;
785 Creature* creatureTarget = (Creature*)unitTarget;
786 if(creatureTarget->isPet())
787 return;
789 GameObject* pGameObj = new GameObject;
791 Map *map = creatureTarget->GetMap();
793 // create before death for get proper coordinates
794 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map, m_caster->GetPhaseMask(),
795 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
796 creatureTarget->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, 1) )
798 delete pGameObj;
799 return;
802 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
803 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
804 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
805 pGameObj->SetSpellId(m_spellInfo->Id);
807 creatureTarget->setDeathState(JUST_DIED);
808 creatureTarget->RemoveCorpse();
809 creatureTarget->SetHealth(0); // just for nice GM-mode view
811 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy");
812 map->Add(pGameObj);
814 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
815 data << uint64(pGameObj->GetGUID());
816 m_caster->SendMessageToSet(&data,true);
818 return;
820 case 23074: // Arcanite Dragonling
821 if (!m_CastItem) return;
822 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
823 return;
824 case 23075: // Mithril Mechanical Dragonling
825 if (!m_CastItem) return;
826 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
827 return;
828 case 23076: // Mechanical Dragonling
829 if (!m_CastItem) return;
830 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
831 return;
832 case 23133: // Gnomish Battle Chicken
833 if (!m_CastItem) return;
834 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
835 return;
836 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
838 int32 r = irand(0, 119);
839 if ( r < 20 ) // 1/6 polymorph
840 m_caster->CastSpell(m_caster,23444,true);
841 else if ( r < 100 ) // 4/6 evil twin
842 m_caster->CastSpell(m_caster,23445,true);
843 else // 1/6 miss the target
844 m_caster->CastSpell(m_caster,36902,true);
845 return;
847 case 23453: // Ultrasafe Transporter: Gadgetzan
848 if ( roll_chance_i(50) ) // success
849 m_caster->CastSpell(m_caster,23441,true);
850 else // failure
851 m_caster->CastSpell(m_caster,23446,true);
852 return;
853 case 23645: // Hourglass Sand
854 m_caster->RemoveAurasDueToSpell(23170);
855 return;
856 case 23725: // Gift of Life (warrior bwl trinket)
857 m_caster->CastSpell(m_caster,23782,true);
858 m_caster->CastSpell(m_caster,23783,true);
859 return;
860 case 25860: // Reindeer Transformation
862 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
863 return;
865 float flyspeed = m_caster->GetSpeedRate(MOVE_FLIGHT);
866 float speed = m_caster->GetSpeedRate(MOVE_RUN);
868 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
870 //5 different spells used depending on mounted speed and if mount can fly or not
871 if (flyspeed >= 4.1f)
872 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
873 else if (flyspeed >= 3.8f)
874 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
875 else if (flyspeed >= 1.6f)
876 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
877 else if (speed >= 2.0f)
878 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
879 else
880 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
882 return;
884 //case 26074: // Holiday Cheer
885 // return; -- implemented at client side
886 case 28006: // Arcane Cloaking
888 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
889 m_caster->CastSpell(unitTarget,29294,true);
890 return;
892 case 28730: // Arcane Torrent (Mana)
894 Aura * dummy = m_caster->GetDummyAura(28734);
895 if (dummy)
897 int32 bp = damage * dummy->GetStackAmount();
898 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
899 m_caster->RemoveAurasDueToSpell(28734);
901 return;
903 case 29200: // Purify Helboar Meat
905 if( m_caster->GetTypeId() != TYPEID_PLAYER )
906 return;
908 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
910 m_caster->CastSpell(m_caster,spell_id,true,NULL);
911 return;
913 case 29858: // Soulshatter
914 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
915 m_caster->CastSpell(unitTarget,32835,true);
916 return;
917 case 30458: // Nigh Invulnerability
918 if (!m_CastItem) return;
919 if(roll_chance_i(86)) // success
920 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
921 else // backfire in 14% casts
922 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
923 return;
924 case 30507: // Poultryizer
925 if (!m_CastItem) return;
926 if(roll_chance_i(80)) // success
927 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
928 else // backfire 20%
929 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
930 return;
931 case 33060: // Make a Wish
933 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
934 return;
936 uint32 spell_id = 0;
938 switch(urand(1,5))
940 case 1: spell_id = 33053; break;
941 case 2: spell_id = 33057; break;
942 case 3: spell_id = 33059; break;
943 case 4: spell_id = 33062; break;
944 case 5: spell_id = 33064; break;
947 m_caster->CastSpell(m_caster,spell_id,true,NULL);
948 return;
950 case 35745:
952 uint32 spell_id;
953 switch(m_caster->GetAreaId())
955 case 3900: spell_id = 35743; break;
956 case 3742: spell_id = 35744; break;
957 default: return;
960 m_caster->CastSpell(m_caster,spell_id,true);
961 return;
963 case 37674: // Chaos Blast
965 if(!unitTarget)
966 return;
968 int32 basepoints0 = 100;
969 m_caster->CastCustomSpell(unitTarget,37675,&basepoints0,NULL,NULL,true);
970 return;
972 case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
974 // selecting one from Bloodstained Fortune item
975 uint32 newitemid;
976 switch(urand(1,20))
978 case 1: newitemid = 32688; break;
979 case 2: newitemid = 32689; break;
980 case 3: newitemid = 32690; break;
981 case 4: newitemid = 32691; break;
982 case 5: newitemid = 32692; break;
983 case 6: newitemid = 32693; break;
984 case 7: newitemid = 32700; break;
985 case 8: newitemid = 32701; break;
986 case 9: newitemid = 32702; break;
987 case 10: newitemid = 32703; break;
988 case 11: newitemid = 32704; break;
989 case 12: newitemid = 32705; break;
990 case 13: newitemid = 32706; break;
991 case 14: newitemid = 32707; break;
992 case 15: newitemid = 32708; break;
993 case 16: newitemid = 32709; break;
994 case 17: newitemid = 32710; break;
995 case 18: newitemid = 32711; break;
996 case 19: newitemid = 32712; break;
997 case 20: newitemid = 32713; break;
998 default:
999 return;
1002 DoCreateItem(i,newitemid);
1003 return;
1005 // Demon Broiled Surprise
1006 /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
1007 case 43723:
1009 if (m_caster->GetTypeId() != TYPEID_PLAYER)
1010 return;
1012 ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
1013 return;
1016 case 44875: // Complete Raptor Capture
1018 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
1019 return;
1021 Creature* creatureTarget = (Creature*)unitTarget;
1023 creatureTarget->setDeathState(JUST_DIED);
1024 creatureTarget->RemoveCorpse();
1025 creatureTarget->SetHealth(0); // just for nice GM-mode view
1027 //cast spell Raptor Capture Credit
1028 m_caster->CastSpell(m_caster,42337,true,NULL);
1029 return;
1031 case 34665: //Administer Antidote
1033 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1034 return;
1036 if(!unitTarget)
1037 return;
1039 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1040 if(!tempSummon)
1041 return;
1043 uint32 health = tempSummon->GetHealth();
1045 float x = tempSummon->GetPositionX();
1046 float y = tempSummon->GetPositionY();
1047 float z = tempSummon->GetPositionZ();
1048 float o = tempSummon->GetOrientation();
1049 tempSummon->UnSummon();
1051 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1052 if (!pCreature)
1053 return;
1055 pCreature->SetHealth(health);
1056 ((Player*)m_caster)->RewardPlayerAndGroupAtEvent(16992,pCreature);
1058 if (pCreature->AI())
1059 pCreature->AI()->AttackStart(m_caster);
1061 return;
1063 case 44997: // Converting Sentry
1065 //Converted Sentry Credit
1066 m_caster->CastSpell(m_caster, 45009, true);
1067 return;
1069 case 45030: // Impale Emissary
1071 // Emissary of Hate Credit
1072 m_caster->CastSpell(m_caster, 45088, true);
1073 return;
1075 case 50243: // Teach Language
1077 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1078 return;
1080 // spell has a 1/3 chance to trigger one of the below
1081 if(roll_chance_i(66))
1082 return;
1083 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1085 // 1000001 - gnomish binary
1086 m_caster->CastSpell(m_caster, 50242, true);
1088 else
1090 // 01001000 - goblin binary
1091 m_caster->CastSpell(m_caster, 50246, true);
1094 return;
1096 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1098 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1099 return;
1101 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1102 bg->EventPlayerDroppedFlag((Player*)m_caster);
1104 m_caster->CastSpell(m_caster, 30452, true, NULL);
1105 return;
1107 case 52308:
1109 switch(i)
1111 case 0:
1113 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
1114 uint32 reqAuraID = m_spellInfo->CalculateSimpleValue(1);
1116 if (m_caster->HasAura(reqAuraID,0))
1117 m_caster->CastSpell(m_caster,spellID,true,NULL);
1118 return;
1120 case 1:
1121 return; // additional data for dummy[0]
1123 return;
1125 case 53341:
1126 case 53343:
1128 m_caster->CastSpell(m_caster,54586,true);
1129 return;
1131 case 58418: // Portal to Orgrimmar
1132 case 58420: // Portal to Stormwind
1133 return; // implemented in EffectScript[0]
1136 //All IconID Check in there
1137 switch(m_spellInfo->SpellIconID)
1139 // Berserking (troll racial traits)
1140 case 1661:
1142 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1143 int32 melee_mod = 10;
1144 if (healthPerc <= 40)
1145 melee_mod = 30;
1146 if (healthPerc < 100 && healthPerc > 40)
1147 melee_mod = 10+(100-healthPerc)/3;
1149 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1150 int32 hasteModBasePoints1 = (5-melee_mod);
1151 int32 hasteModBasePoints2 = 5;
1153 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1154 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1155 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1156 return;
1159 break;
1161 case SPELLFAMILY_MAGE:
1162 switch(m_spellInfo->Id )
1164 case 11958: // Cold Snap
1166 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1167 return;
1169 // immediately finishes the cooldown on Frost spells
1170 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1171 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1173 if (itr->second->state == PLAYERSPELL_REMOVED)
1174 continue;
1176 uint32 classspell = itr->first;
1177 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1179 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1180 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1181 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1183 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1185 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1186 data << uint32(classspell);
1187 data << uint64(m_caster->GetGUID());
1188 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1191 return;
1193 case 32826:
1195 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1197 //Polymorph Cast Visual Rank 1
1198 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1199 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1201 return;
1204 break;
1205 case SPELLFAMILY_WARRIOR:
1206 // Charge
1207 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual[0] == 867)
1209 int32 chargeBasePoints0 = damage;
1210 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1211 return;
1213 // Execute
1214 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1216 if(!unitTarget)
1217 return;
1219 uint32 rage = m_caster->GetPower(POWER_RAGE);
1220 // Glyph of Execution bonus
1221 if (Aura *aura = m_caster->GetDummyAura(58367))
1222 rage+=aura->GetModifier()->m_amount;
1224 int32 basePoints0 = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
1225 m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
1226 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1227 m_caster->SetPower(POWER_RAGE,0);
1228 return;
1230 // Slam
1231 if(m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL)
1233 if(!unitTarget)
1234 return;
1235 m_damage+=m_caster->CalculateDamage(m_attackType, false);
1236 m_damage+=damage;
1237 return;
1239 switch(m_spellInfo->Id)
1241 // Warrior's Wrath
1242 case 21977:
1244 if(!unitTarget)
1245 return;
1246 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1247 return;
1249 // Last Stand
1250 case 12975:
1252 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
1253 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
1254 return;
1256 // Bloodthirst
1257 case 23881:
1259 m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
1260 return;
1263 break;
1264 case SPELLFAMILY_WARLOCK:
1265 // Life Tap
1266 if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL)
1268 // In 303 exist spirit depend
1269 uint32 spirit = uint32(m_caster->GetStat(STAT_SPIRIT));
1270 switch (m_spellInfo->Id)
1272 case 1454: damage+=spirit; break;
1273 case 1455: damage+=spirit*15/10; break;
1274 case 1456: damage+=spirit*2; break;
1275 case 11687: damage+=spirit*25/10; break;
1276 case 11688:
1277 case 11689:
1278 case 27222:
1279 case 57946: damage+=spirit*3; break;
1280 default:
1281 sLog.outError("Spell::EffectDummy: %u Life Tap need set spirit multipler", m_spellInfo->Id);
1282 return;
1284 // Think its not need (also need remove Life Tap from SpellDamageBonus or add new value)
1285 // damage = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(damage > 0 ? damage : 0), SPELL_DIRECT_DAMAGE);
1286 if(int32(unitTarget->GetHealth()) > damage)
1288 // Shouldn't Appear in Combat Log
1289 unitTarget->ModifyHealth(-damage);
1291 int32 mana = damage;
1292 // Improved Life Tap mod
1293 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1294 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1296 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1297 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1299 m_caster->CastCustomSpell(unitTarget, 31818, &mana, NULL, NULL, true);
1301 // Mana Feed
1302 int32 manaFeedVal = 0;
1303 Unit::AuraList const& mod = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
1304 for(Unit::AuraList::const_iterator itr = mod.begin(); itr != mod.end(); ++itr)
1306 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 1982)
1307 manaFeedVal+= (*itr)->GetModifier()->m_amount;
1309 if(manaFeedVal > 0)
1311 manaFeedVal = manaFeedVal * mana / 100;
1312 m_caster->CastCustomSpell(m_caster, 32553, &manaFeedVal, NULL, NULL, true, NULL);
1315 else
1316 SendCastResult(SPELL_FAILED_FIZZLE);
1317 return;
1319 break;
1320 case SPELLFAMILY_PRIEST:
1321 // Penance
1322 if (m_spellInfo->SpellFamilyFlags & 0x0080000000000000LL)
1324 if (!unitTarget)
1325 return;
1327 int hurt = 0;
1328 int heal = 0;
1329 switch(m_spellInfo->Id)
1331 case 47540: hurt = 47758; heal = 47757; break;
1332 case 53005: hurt = 53001; heal = 52986; break;
1333 case 53006: hurt = 53002; heal = 52987; break;
1334 case 53007: hurt = 53003; heal = 52988; break;
1335 default:
1336 sLog.outError("Spell::EffectDummy: Spell %u Penance need set correct heal/damage spell", m_spellInfo->Id);
1337 return;
1339 if (m_caster->IsFriendlyTo(unitTarget))
1340 m_caster->CastSpell(unitTarget, heal, true, 0);
1341 else
1342 m_caster->CastSpell(unitTarget, hurt, true, 0);
1343 return;
1345 break;
1346 case SPELLFAMILY_DRUID:
1347 // Starfall
1348 if (m_spellInfo->SpellFamilyFlags2 & 0x00000100LL)
1350 //Shapeshifting into an animal form or mounting cancels the effect.
1351 if(m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted())
1353 if(m_triggeredByAuraSpell)
1354 m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id);
1355 return;
1358 //Any effect which causes you to lose control of your character will supress the starfall effect.
1359 if(m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED))
1360 return;
1362 switch(m_spellInfo->Id)
1364 case 50286: m_caster->CastSpell(unitTarget, 50288, true); return;
1365 case 53196: m_caster->CastSpell(unitTarget, 53191, true); return;
1366 case 53197: m_caster->CastSpell(unitTarget, 53194, true); return;
1367 case 53198: m_caster->CastSpell(unitTarget, 53195, true); return;
1368 default:
1369 sLog.outError("Spell::EffectDummy: Unhandeled Starfall spell rank %u",m_spellInfo->Id);
1370 return;
1373 break;
1374 case SPELLFAMILY_ROGUE:
1375 switch(m_spellInfo->Id )
1377 case 5938: // Shiv
1379 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1380 return;
1382 Player *pCaster = ((Player*)m_caster);
1384 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1385 if(!item)
1386 return;
1388 // all poison enchantments is temporary
1389 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1390 if(!enchant_id)
1391 return;
1393 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1394 if(!pEnchant)
1395 return;
1397 for (int s=0;s<3;s++)
1399 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1400 continue;
1402 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1403 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1404 continue;
1406 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1409 m_caster->CastSpell(unitTarget, 5940, true);
1410 return;
1412 case 14185: // Preparation Rogue
1414 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1415 return;
1417 //immediately finishes the cooldown on certain Rogue abilities
1418 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1419 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1421 uint32 classspell = itr->first;
1422 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1424 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x0000024000000860LL))
1426 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1428 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1429 data << uint32(classspell);
1430 data << uint64(m_caster->GetGUID());
1431 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1434 return;
1436 case 31231: // Cheat Death
1438 m_caster->CastSpell(m_caster,45182,true);
1439 return;
1442 break;
1443 case SPELLFAMILY_HUNTER:
1444 // Steady Shot
1445 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1447 if( !unitTarget || !unitTarget->isAlive())
1448 return;
1450 bool found = false;
1452 // check dazed affect
1453 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1454 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1456 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1458 found = true;
1459 break;
1463 if(found)
1464 m_damage+= damage;
1465 return;
1468 switch(m_spellInfo->Id)
1470 case 23989: //Readiness talent
1472 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1473 return;
1475 //immediately finishes the cooldown for hunter abilities
1476 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1477 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1479 uint32 classspell = itr->first;
1480 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1482 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1484 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1486 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1487 data << uint32(classspell);
1488 data << uint64(m_caster->GetGUID());
1489 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1492 return;
1494 case 37506: // Scatter Shot
1496 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1497 return;
1499 // break Auto Shot and autohit
1500 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1501 m_caster->AttackStop();
1502 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1503 return;
1506 break;
1507 case SPELLFAMILY_PALADIN:
1508 switch(m_spellInfo->SpellIconID)
1510 case 156: // Holy Shock
1512 if(!unitTarget)
1513 return;
1515 int hurt = 0;
1516 int heal = 0;
1518 switch(m_spellInfo->Id)
1520 case 20473: hurt = 25912; heal = 25914; break;
1521 case 20929: hurt = 25911; heal = 25913; break;
1522 case 20930: hurt = 25902; heal = 25903; break;
1523 case 27174: hurt = 27176; heal = 27175; break;
1524 case 33072: hurt = 33073; heal = 33074; break;
1525 case 48824: hurt = 48822; heal = 48820; break;
1526 case 48825: hurt = 48823; heal = 48821; break;
1527 default:
1528 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1529 return;
1532 if(m_caster->IsFriendlyTo(unitTarget))
1533 m_caster->CastSpell(unitTarget, heal, true, 0);
1534 else
1535 m_caster->CastSpell(unitTarget, hurt, true, 0);
1537 return;
1539 case 561: // Judgement of command
1541 if(!unitTarget)
1542 return;
1544 uint32 spell_id = m_currentBasePoints[i]+1;
1545 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1546 if(!spell_proto)
1547 return;
1549 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1551 // decreased damage (/2) for non-stunned target.
1552 SpellModifier *mod = new SpellModifier;
1553 mod->op = SPELLMOD_DAMAGE;
1554 mod->value = -50;
1555 mod->type = SPELLMOD_PCT;
1556 mod->spellId = m_spellInfo->Id;
1557 mod->mask = 0x0000020000000000LL;
1558 mod->mask2= 0LL;
1560 ((Player*)m_caster)->AddSpellMod(mod, true);
1561 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1562 // mod deleted
1563 ((Player*)m_caster)->AddSpellMod(mod, false);
1565 else
1566 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1568 return;
1572 switch(m_spellInfo->Id)
1574 // Judgement of Righteousness (0.2*$AP+0.32*$SPH) holy added in spellDamagBonus
1575 case 20187:
1577 if (!unitTarget)
1578 return;
1579 m_damage+=int32(0.2f*m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
1580 return;
1582 case 31789: // Righteous Defense (step 1)
1584 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1586 // non-standard cast requirement check
1587 if (!unitTarget || unitTarget->getAttackers().empty())
1589 // clear cooldown at fail
1590 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1592 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1594 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1595 data << uint32(m_spellInfo->Id);
1596 data << uint64(m_caster->GetGUID());
1597 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1600 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1601 return;
1604 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1605 // Clear targets for eff 1
1606 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1607 ihit->effectMask &= ~(1<<1);
1609 // not empty (checked)
1610 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1612 // chance to be selected from list
1613 float chance = 100.0f/attackers.size();
1614 uint32 count=0;
1615 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1617 if(!roll_chance_f(chance))
1618 continue;
1619 ++count;
1620 AddUnitTarget((*aItr), 1);
1623 // now let next effect cast spell at each target.
1624 return;
1626 case 37877: // Blessing of Faith
1628 if(!unitTarget)
1629 return;
1631 uint32 spell_id = 0;
1632 switch(unitTarget->getClass())
1634 case CLASS_DRUID: spell_id = 37878; break;
1635 case CLASS_PALADIN: spell_id = 37879; break;
1636 case CLASS_PRIEST: spell_id = 37880; break;
1637 case CLASS_SHAMAN: spell_id = 37881; break;
1638 default: return; // ignore for not healing classes
1641 m_caster->CastSpell(m_caster,spell_id,true);
1642 return;
1645 break;
1646 case SPELLFAMILY_SHAMAN:
1647 //Shaman Rockbiter Weapon
1648 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1650 // TODO: use expect spell for enchant (if exist talent)
1651 // In 3.0.3 no mods present for rockbiter
1652 uint32 spell_id = 0;
1653 switch(m_spellInfo->Id)
1655 case 8017: spell_id = 36494; break; // Rank 1
1656 case 8018: spell_id = 36750; break; // Rank 2
1657 case 8019: spell_id = 36755; break; // Rank 3
1658 case 10399: spell_id = 36759; break; // Rank 4
1659 default:
1660 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1661 return;
1664 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1666 if(!spellInfo)
1668 sLog.outError("WORLD: unknown spell id %i", spell_id);
1669 return;
1672 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1673 return;
1675 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1677 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1679 if(item->IsFitToSpellRequirements(m_spellInfo))
1681 Spell *spell = new Spell(m_caster, spellInfo, true);
1683 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1684 // at calculation applied affect from Elemental Weapons talent
1685 // real enchantment damage-1
1686 spell->m_currentBasePoints[1] = damage-1;
1688 SpellCastTargets targets;
1689 targets.setItemTarget( item );
1690 spell->prepare(&targets);
1694 return;
1696 // Healing Stream Totem
1697 if(m_spellInfo->SpellFamilyFlags & 0x0000000000002000LL)
1699 m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1700 return;
1702 // Mana Spring Totem
1703 if(m_spellInfo->SpellFamilyFlags & 0x0000000000004000LL)
1705 if(unitTarget->getPowerType()!=POWER_MANA)
1706 return;
1707 m_caster->CastCustomSpell(unitTarget, 52032, &damage, 0, 0, true, 0, 0, m_originalCasterGUID);
1708 return;
1710 if(m_spellInfo->Id == 39610) // Mana Tide Totem effect
1712 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1713 return;
1714 // Glyph of Mana Tide
1715 Unit *owner = m_caster->GetOwner();
1716 if (owner)
1717 if (Aura *dummy = owner->GetDummyAura(55441))
1718 damage+=dummy->GetModifier()->m_amount;
1719 // Regenerate 6% of Total Mana Every 3 secs
1720 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1721 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1722 return;
1724 // Lava Lash
1725 if (m_spellInfo->SpellFamilyFlags2 & 0x00000004)
1727 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1728 return;
1729 Item *item = ((Player*)m_caster)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
1730 if (item)
1732 // Damage is increased if your off-hand weapon is enchanted with Flametongue.
1733 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1734 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1736 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_SHAMAN &&
1737 (*itr)->GetSpellProto()->SpellFamilyFlags & 0x0000000000200000LL &&
1738 (*itr)->GetCastItemGUID() == item->GetGUID())
1740 m_damage += m_damage * damage / 100;
1741 return;
1745 return;
1747 break;
1748 case SPELLFAMILY_DEATHKNIGHT:
1749 // Death Coil
1750 if(m_spellInfo->SpellFamilyFlags & 0x002000LL)
1752 if(m_caster->IsFriendlyTo(unitTarget))
1754 if(unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
1755 return;
1757 int32 bp = damage * 1.5f;
1758 m_caster->CastCustomSpell(unitTarget,47633,&bp,NULL,NULL,true);
1760 else
1762 int32 bp = damage;
1763 m_caster->CastCustomSpell(unitTarget,47632,&bp,NULL,NULL,true);
1765 return;
1767 break;
1770 // pet auras
1771 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1773 m_caster->AddPetAura(petSpell);
1774 return;
1777 // Script based implementation. Must be used only for not good for implementation in core spell effects
1778 // So called only for not proccessed cases
1779 if(gameObjTarget)
1780 Script->EffectDummyGameObj(m_caster, m_spellInfo->Id, i, gameObjTarget);
1781 else if(unitTarget && unitTarget->GetTypeId()==TYPEID_UNIT)
1782 Script->EffectDummyCreature(m_caster, m_spellInfo->Id, i, (Creature*)unitTarget);
1783 else if(itemTarget)
1784 Script->EffectDummyItem(m_caster, m_spellInfo->Id, i, itemTarget);
1787 void Spell::EffectTriggerSpellWithValue(uint32 i)
1789 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1791 // normal case
1792 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1794 if(!spellInfo)
1796 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1797 return;
1800 int32 bp = damage;
1801 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1804 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1806 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1807 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1809 if(!spellInfo)
1811 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1812 return;
1815 finish();
1816 Spell *spell = new Spell(m_caster, spellInfo, true);
1818 SpellCastTargets targets;
1819 targets.setUnitTarget( unitTarget);
1820 spell->prepare(&targets);
1822 m_caster->SetCurrentCastedSpell(spell);
1823 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1827 void Spell::EffectForceCast(uint32 i)
1829 if( !unitTarget )
1830 return;
1832 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1834 // normal case
1835 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1837 if(!spellInfo)
1839 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1840 return;
1843 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1846 void Spell::EffectTriggerSpell(uint32 i)
1848 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1850 // special cases
1851 switch(triggered_spell_id)
1853 // Vanish
1854 case 18461:
1856 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1857 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1858 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1860 // if this spell is given to NPC it must handle rest by it's own AI
1861 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1862 return;
1864 // get highest rank of the Stealth spell
1865 uint32 spellId = 0;
1866 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1867 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1869 // only highest rank is shown in spell book, so simply check if shown in spell book
1870 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1871 continue;
1873 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1874 if (!spellInfo)
1875 continue;
1877 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1879 spellId = spellInfo->Id;
1880 break;
1884 // no Stealth spell found
1885 if (!spellId)
1886 return;
1888 // reset cooldown on it if needed
1889 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1890 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1892 m_caster->CastSpell(m_caster, spellId, true);
1893 return;
1895 // just skip
1896 case 23770: // Sayge's Dark Fortune of *
1897 // not exist, common cooldown can be implemented in scripts if need.
1898 return;
1899 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1900 case 29284:
1902 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1903 if (!spell)
1904 return;
1906 for (int i=0; i < spell->StackAmount; ++i)
1907 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1908 return;
1910 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1911 case 29286:
1913 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1914 if (!spell)
1915 return;
1917 for (int i=0; i < spell->StackAmount; ++i)
1918 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1919 return;
1921 // Righteous Defense
1922 case 31980:
1924 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1925 return;
1927 // Cloak of Shadows
1928 case 35729 :
1930 Unit::AuraMap& Auras = m_caster->GetAuras();
1931 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1933 // remove all harmful spells on you...
1934 if( // ignore positive and passive auras
1935 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1936 // ignore physical auras
1937 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 )
1939 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1940 iter = Auras.begin();
1943 return;
1945 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1946 case 41967:
1948 if (Unit *pet = m_caster->GetPet())
1949 pet->CastSpell(pet, 28305, true);
1950 return;
1954 // normal case
1955 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1957 if(!spellInfo)
1959 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1960 return;
1963 // some triggered spells require specific equipment
1964 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1966 // main hand weapon required
1967 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1969 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1971 // skip spell if no weapon in slot or broken
1972 if(!item || item->IsBroken() )
1973 return;
1975 // skip spell if weapon not fit to triggered spell
1976 if(!item->IsFitToSpellRequirements(spellInfo))
1977 return;
1980 // offhand hand weapon required
1981 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1983 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1985 // skip spell if no weapon in slot or broken
1986 if(!item || item->IsBroken() )
1987 return;
1989 // skip spell if weapon not fit to triggered spell
1990 if(!item->IsFitToSpellRequirements(spellInfo))
1991 return;
1995 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1996 bool instant = false;
1997 for(uint32 j = i+1; j < 3; ++j)
1999 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
2001 instant = true;
2002 break;
2006 if(instant)
2008 if (unitTarget)
2009 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
2011 else
2012 m_TriggerSpells.push_back(spellInfo);
2015 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
2017 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
2019 // normal case
2020 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
2022 if(!spellInfo)
2024 sLog.outError("EffectTriggerMissileSpell of spell %u (eff: %u): triggering unknown spell id %u",
2025 m_spellInfo->Id,effect_idx,triggered_spell_id);
2026 return;
2029 if (m_CastItem)
2030 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
2032 m_caster->CastSpell(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, spellInfo, true, m_CastItem, 0, m_originalCasterGUID);
2035 void Spell::EffectJump(uint32 i)
2037 if(m_caster->isInFlight())
2038 return;
2040 // Init dest coordinates
2041 float x,y,z,o;
2042 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
2044 x = m_targets.m_destX;
2045 y = m_targets.m_destY;
2046 z = m_targets.m_destZ;
2048 if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_BEHIND_VICTIM)
2050 // explicit cast data from client or server-side cast
2051 // some spell at client send caster
2052 Unit* pTarget = NULL;
2053 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=m_caster)
2054 pTarget = m_targets.getUnitTarget();
2055 else if(unitTarget->getVictim())
2056 pTarget = m_caster->getVictim();
2057 else if(m_caster->GetTypeId() == TYPEID_PLAYER)
2058 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
2060 o = pTarget ? pTarget->GetOrientation() : m_caster->GetOrientation();
2062 else
2063 o = m_caster->GetOrientation();
2065 else if(unitTarget)
2067 unitTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2068 o = m_caster->GetOrientation();
2070 else if(gameObjTarget)
2072 gameObjTarget->GetContactPoint(m_caster,x,y,z,CONTACT_DISTANCE);
2073 o = m_caster->GetOrientation();
2075 else
2077 sLog.outError( "Spell::EffectJump - unsupported target mode for spell ID %u", m_spellInfo->Id );
2078 return;
2081 m_caster->NearTeleportTo(x,y,z,o,true);
2084 void Spell::EffectTeleportUnits(uint32 i)
2086 if(!unitTarget || unitTarget->isInFlight())
2087 return;
2089 switch (m_spellInfo->EffectImplicitTargetB[i])
2091 case TARGET_INNKEEPER_COORDINATES:
2093 // Only players can teleport to innkeeper
2094 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
2095 return;
2097 ((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);
2098 return;
2100 case TARGET_TABLE_X_Y_Z_COORDINATES:
2102 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
2103 if(!st)
2105 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id );
2106 return;
2109 if(st->target_mapId==unitTarget->GetMapId())
2110 unitTarget->NearTeleportTo(st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster);
2111 else if(unitTarget->GetTypeId()==TYPEID_PLAYER)
2112 ((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);
2113 break;
2115 case TARGET_BEHIND_VICTIM:
2117 Unit *pTarget = NULL;
2119 // explicit cast data from client or server-side cast
2120 // some spell at client send caster
2121 if(m_targets.getUnitTarget() && m_targets.getUnitTarget()!=unitTarget)
2122 pTarget = m_targets.getUnitTarget();
2123 else if(unitTarget->getVictim())
2124 pTarget = unitTarget->getVictim();
2125 else if(unitTarget->GetTypeId() == TYPEID_PLAYER)
2126 pTarget = ObjectAccessor::GetUnit(*unitTarget, ((Player*)unitTarget)->GetSelection());
2128 // Init dest coordinates
2129 float x = m_targets.m_destX;
2130 float y = m_targets.m_destY;
2131 float z = m_targets.m_destZ;
2132 float orientation = pTarget ? pTarget->GetOrientation() : unitTarget->GetOrientation();
2133 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2134 return;
2136 default:
2138 // If not exist data for dest location - return
2139 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
2141 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
2142 return;
2144 // Init dest coordinates
2145 uint32 mapid = m_caster->GetMapId();
2146 float x = m_targets.m_destX;
2147 float y = m_targets.m_destY;
2148 float z = m_targets.m_destZ;
2149 float orientation = unitTarget->GetOrientation();
2150 // Teleport
2151 unitTarget->NearTeleportTo(x,y,z,orientation,unitTarget==m_caster);
2152 return;
2156 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
2157 switch ( m_spellInfo->Id )
2159 // Dimensional Ripper - Everlook
2160 case 23442:
2162 int32 r = irand(0, 119);
2163 if ( r >= 70 ) // 7/12 success
2165 if ( r < 100 ) // 4/12 evil twin
2166 m_caster->CastSpell(m_caster,23445,true);
2167 else // 1/12 fire
2168 m_caster->CastSpell(m_caster,23449,true);
2170 return;
2172 // Ultrasafe Transporter: Toshley's Station
2173 case 36941:
2175 if ( roll_chance_i(50) ) // 50% success
2177 int32 rand_eff = urand(1,7);
2178 switch ( rand_eff )
2180 case 1:
2181 // soul split - evil
2182 m_caster->CastSpell(m_caster,36900,true);
2183 break;
2184 case 2:
2185 // soul split - good
2186 m_caster->CastSpell(m_caster,36901,true);
2187 break;
2188 case 3:
2189 // Increase the size
2190 m_caster->CastSpell(m_caster,36895,true);
2191 break;
2192 case 4:
2193 // Decrease the size
2194 m_caster->CastSpell(m_caster,36893,true);
2195 break;
2196 case 5:
2197 // Transform
2199 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2200 m_caster->CastSpell(m_caster,36897,true);
2201 else
2202 m_caster->CastSpell(m_caster,36899,true);
2203 break;
2205 case 6:
2206 // chicken
2207 m_caster->CastSpell(m_caster,36940,true);
2208 break;
2209 case 7:
2210 // evil twin
2211 m_caster->CastSpell(m_caster,23445,true);
2212 break;
2215 return;
2217 // Dimensional Ripper - Area 52
2218 case 36890:
2220 if ( roll_chance_i(50) ) // 50% success
2222 int32 rand_eff = urand(1,4);
2223 switch ( rand_eff )
2225 case 1:
2226 // soul split - evil
2227 m_caster->CastSpell(m_caster,36900,true);
2228 break;
2229 case 2:
2230 // soul split - good
2231 m_caster->CastSpell(m_caster,36901,true);
2232 break;
2233 case 3:
2234 // Increase the size
2235 m_caster->CastSpell(m_caster,36895,true);
2236 break;
2237 case 4:
2238 // Transform
2240 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2241 m_caster->CastSpell(m_caster,36897,true);
2242 else
2243 m_caster->CastSpell(m_caster,36899,true);
2244 break;
2248 return;
2253 void Spell::EffectApplyAura(uint32 i)
2255 if(!unitTarget)
2256 return;
2258 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2259 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2260 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2261 return;
2263 Unit* caster = m_originalCaster ? m_originalCaster : m_caster;
2264 if(!caster)
2265 return;
2267 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2269 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2271 // Now Reduce spell duration using data received at spell hit
2272 int32 duration = Aur->GetAuraMaxDuration();
2273 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2274 Aur->setDiminishGroup(m_diminishGroup);
2276 // if Aura removed and deleted, do not continue.
2277 if(duration== 0 && !(Aur->IsPermanent()))
2279 delete Aur;
2280 return;
2283 if(duration != Aur->GetAuraMaxDuration())
2285 Aur->SetAuraMaxDuration(duration);
2286 Aur->SetAuraDuration(duration);
2289 bool added = unitTarget->AddAura(Aur);
2291 // Aura not added and deleted in AddAura call;
2292 if (!added)
2293 return;
2295 // found crash at character loading, broken pointer to Aur...
2296 // Aur was deleted in AddAura()...
2297 if(!Aur)
2298 return;
2300 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2301 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2302 m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
2305 void Spell::EffectUnlearnSpecialization( uint32 i )
2307 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2308 return;
2310 Player *_player = (Player*)unitTarget;
2311 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2313 _player->removeSpell(spellToUnlearn);
2315 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2318 void Spell::EffectPowerDrain(uint32 i)
2320 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2321 return;
2323 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2325 if(!unitTarget)
2326 return;
2327 if(!unitTarget->isAlive())
2328 return;
2329 if(unitTarget->getPowerType() != drain_power)
2330 return;
2331 if(damage < 0)
2332 return;
2334 uint32 curPower = unitTarget->GetPower(drain_power);
2336 //add spell damage bonus
2337 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2339 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2340 uint32 power = damage;
2341 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2342 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2344 int32 new_damage;
2345 if(curPower < power)
2346 new_damage = curPower;
2347 else
2348 new_damage = power;
2350 unitTarget->ModifyPower(drain_power,-new_damage);
2352 // Don`t restore from self drain
2353 if(drain_power == POWER_MANA && m_caster != unitTarget)
2355 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2356 if(manaMultiplier==0)
2357 manaMultiplier = 1;
2359 if(Player *modOwner = m_caster->GetSpellModOwner())
2360 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2362 int32 gain = int32(new_damage*manaMultiplier);
2364 m_caster->ModifyPower(POWER_MANA,gain);
2365 //send log
2366 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA);
2370 void Spell::EffectSendEvent(uint32 EffectIndex)
2373 we do not handle a flag dropping or clicking on flag in battleground by sendevent system
2375 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2376 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2379 void Spell::EffectPowerBurn(uint32 i)
2381 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2382 return;
2384 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2386 if(!unitTarget)
2387 return;
2388 if(!unitTarget->isAlive())
2389 return;
2390 if(unitTarget->getPowerType()!=powertype)
2391 return;
2392 if(damage < 0)
2393 return;
2395 // burn x% of target's mana, up to maximum of 2x% of caster's mana (Mana Burn)
2396 if(m_spellInfo->ManaCostPercentage)
2398 uint32 maxdamage = m_caster->GetMaxPower(powertype) * damage * 2 / 100;
2399 damage = unitTarget->GetMaxPower(powertype) * damage / 100;
2400 if(damage > maxdamage) damage = maxdamage;
2403 int32 curPower = int32(unitTarget->GetPower(powertype));
2405 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2406 uint32 power = damage;
2407 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2408 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2410 int32 new_damage = (curPower < power) ? curPower : power;
2412 unitTarget->ModifyPower(powertype,-new_damage);
2413 float multiplier = m_spellInfo->EffectMultipleValue[i];
2415 if(Player *modOwner = m_caster->GetSpellModOwner())
2416 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2418 new_damage = int32(new_damage*multiplier);
2419 m_damage+=new_damage;
2422 void Spell::EffectHeal( uint32 /*i*/ )
2424 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2426 // Try to get original caster
2427 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2429 // Skip if m_originalCaster not available
2430 if (!caster)
2431 return;
2433 int32 addhealth = damage;
2435 // Vessel of the Naaru (Vial of the Sunwell trinket)
2436 if (m_spellInfo->Id == 45064)
2438 // Amount of heal - depends from stacked Holy Energy
2439 int damageAmount = 0;
2440 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2441 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2442 if((*i)->GetId() == 45062)
2443 damageAmount+=(*i)->GetModifier()->m_amount;
2444 if (damageAmount)
2445 m_caster->RemoveAurasDueToSpell(45062);
2447 addhealth += damageAmount;
2449 // Swiftmend - consumes Regrowth or Rejuvenation
2450 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2452 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2453 // find most short by duration
2454 Aura *targetAura = NULL;
2455 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2457 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2458 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2460 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2461 targetAura = *i;
2465 if(!targetAura)
2467 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2468 return;
2470 int idx = 0;
2471 while(idx < 3)
2473 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2474 break;
2475 idx++;
2478 int32 tickheal = caster->SpellHealingBonus(unitTarget, targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT);
2479 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2480 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2482 addhealth += tickheal * tickcount;
2484 else
2485 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, addhealth, HEAL);
2487 m_healing+=addhealth;
2491 void Spell::EffectHealPct( uint32 /*i*/ )
2493 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2495 // Try to get original caster
2496 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2498 // Skip if m_originalCaster not available
2499 if (!caster)
2500 return;
2502 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2503 if(Player* modOwner = m_caster->GetSpellModOwner())
2504 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DAMAGE, addhealth, this);
2506 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2508 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2509 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2511 if(caster->GetTypeId()==TYPEID_PLAYER)
2512 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2513 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2517 void Spell::EffectHealMechanical( uint32 /*i*/ )
2519 // Mechanic creature type should be correctly checked by targetCreatureType field
2520 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2522 // Try to get original caster
2523 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2525 // Skip if m_originalCaster not available
2526 if (!caster)
2527 return;
2529 uint32 addhealth = caster->SpellHealingBonus(unitTarget, m_spellInfo, uint32(damage), HEAL);
2530 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2531 unitTarget->ModifyHealth( int32(damage) );
2535 void Spell::EffectHealthLeech(uint32 i)
2537 if(!unitTarget)
2538 return;
2539 if(!unitTarget->isAlive())
2540 return;
2542 if(damage < 0)
2543 return;
2545 sLog.outDebug("HealthLeech :%i", damage);
2547 float multiplier = m_spellInfo->EffectMultipleValue[i];
2549 if(Player *modOwner = m_caster->GetSpellModOwner())
2550 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2552 int32 new_damage = int32(damage*multiplier);
2553 uint32 curHealth = unitTarget->GetHealth();
2554 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2555 if(curHealth < new_damage)
2556 new_damage = curHealth;
2558 if(m_caster->isAlive())
2560 new_damage = m_caster->SpellHealingBonus(m_caster, m_spellInfo, new_damage, HEAL);
2562 m_caster->ModifyHealth(new_damage);
2564 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2565 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2567 // m_healthLeech+=tmpvalue;
2568 // m_damage+=new_damage;
2571 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2573 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2574 return;
2576 Player* player = (Player*)unitTarget;
2578 uint32 newitemid = itemtype;
2579 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2580 if(!pProto)
2582 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2583 return;
2586 uint32 num_to_add;
2588 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2589 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2591 int32 basePoints = m_currentBasePoints[i];
2592 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2593 if (randomPoints)
2594 num_to_add = basePoints + irand(1, randomPoints);
2595 else
2596 num_to_add = basePoints + 1;
2598 else if (pProto->MaxCount == 1)
2599 num_to_add = 1;
2600 else if(player->getLevel() >= m_spellInfo->spellLevel)
2602 int32 basePoints = m_currentBasePoints[i];
2603 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2604 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2606 else
2607 num_to_add = 2;
2609 if (num_to_add < 1)
2610 num_to_add = 1;
2611 if (num_to_add > pProto->GetMaxStackSize())
2612 num_to_add = pProto->GetMaxStackSize();
2614 // init items_count to 1, since 1 item will be created regardless of specialization
2615 int items_count=1;
2616 // the chance to create additional items
2617 float additionalCreateChance=0.0f;
2618 // the maximum number of created additional items
2619 uint8 additionalMaxNum=0;
2620 // get the chance and maximum number for creating extra items
2621 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2623 // roll with this chance till we roll not to create or we create the max num
2624 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2625 ++items_count;
2628 // really will be created more items
2629 num_to_add *= items_count;
2631 // can the player store the new item?
2632 ItemPosCountVec dest;
2633 uint32 no_space = 0;
2634 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2635 if( msg != EQUIP_ERR_OK )
2637 // convert to possible store amount
2638 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2639 num_to_add -= no_space;
2640 else
2642 // if not created by another reason from full inventory or unique items amount limitation
2643 player->SendEquipError( msg, NULL, NULL );
2644 return;
2648 if(num_to_add)
2650 // create the new item and store it
2651 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2653 // was it successful? return error if not
2654 if(!pItem)
2656 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2657 return;
2660 // set the "Crafted by ..." property of the item
2661 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2662 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2664 // send info to the client
2665 if(pItem)
2666 player->SendNewItem(pItem, num_to_add, true, true);
2668 // we succeeded in creating at least one item, so a levelup is possible
2669 player->UpdateCraftSkill(m_spellInfo->Id);
2672 // for battleground marks send by mail if not add all expected
2673 if(no_space > 0 )
2675 BattleGroundTypeId bgType;
2676 switch(m_spellInfo->Id)
2678 case SPELL_AV_MARK_WINNER:
2679 case SPELL_AV_MARK_LOSER:
2680 bgType = BATTLEGROUND_AV;
2681 break;
2682 case SPELL_WS_MARK_WINNER:
2683 case SPELL_WS_MARK_LOSER:
2684 bgType = BATTLEGROUND_WS;
2685 break;
2686 case SPELL_AB_MARK_WINNER:
2687 case SPELL_AB_MARK_LOSER:
2688 bgType = BATTLEGROUND_AB;
2689 break;
2690 default:
2691 return;
2694 if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
2695 bg->SendRewardMarkByMail(player,newitemid,no_space);
2699 void Spell::EffectCreateItem(uint32 i)
2701 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2704 void Spell::EffectCreateItem2(uint32 i)
2706 // special case: generate using spell_loot_template
2707 if(!m_spellInfo->EffectItemType[i])
2709 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
2710 return;
2712 // create some random items
2713 ((Player*)m_caster)->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
2714 return;
2716 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2719 void Spell::EffectPersistentAA(uint32 i)
2721 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2723 if(Player* modOwner = m_caster->GetSpellModOwner())
2724 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2726 int32 duration = GetSpellDuration(m_spellInfo);
2727 DynamicObject* dynObj = new DynamicObject;
2728 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))
2730 delete dynObj;
2731 return;
2733 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2734 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2735 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2736 m_caster->AddDynObject(dynObj);
2737 dynObj->GetMap()->Add(dynObj);
2740 void Spell::EffectEnergize(uint32 i)
2742 if(!unitTarget)
2743 return;
2744 if(!unitTarget->isAlive())
2745 return;
2747 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2748 return;
2750 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2752 // Some level depends spells
2753 int multiplier = 0;
2754 int level_diff = 0;
2755 switch (m_spellInfo->Id)
2757 // Restore Energy
2758 case 9512:
2759 level_diff = m_caster->getLevel() - 40;
2760 multiplier = 2;
2761 break;
2762 // Blood Fury
2763 case 24571:
2764 level_diff = m_caster->getLevel() - 60;
2765 multiplier = 10;
2766 break;
2767 // Burst of Energy
2768 case 24532:
2769 level_diff = m_caster->getLevel() - 60;
2770 multiplier = 4;
2771 break;
2772 default:
2773 break;
2776 if (level_diff > 0)
2777 damage -= multiplier * level_diff;
2779 if(damage < 0)
2780 return;
2782 if(unitTarget->GetMaxPower(power) == 0)
2783 return;
2785 unitTarget->ModifyPower(power,damage);
2786 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2788 // Mad Alchemist's Potion
2789 if (m_spellInfo->Id == 45051)
2791 // find elixirs on target
2792 uint32 elixir_mask = 0;
2793 Unit::AuraMap& Auras = unitTarget->GetAuras();
2794 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2796 uint32 spell_id = itr->second->GetId();
2797 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2798 elixir_mask |= mask;
2801 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2802 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2804 // get all available elixirs by mask and spell level
2805 std::vector<uint32> elixirs;
2806 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2807 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2809 if (itr->second & elixir_mask)
2811 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2812 continue;
2814 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2815 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2816 continue;
2818 elixirs.push_back(itr->first);
2822 if (!elixirs.empty())
2824 // cast random elixir on target
2825 uint32 rand_spell = urand(0,elixirs.size()-1);
2826 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2831 void Spell::EffectEnergisePct(uint32 i)
2833 if(!unitTarget)
2834 return;
2835 if(!unitTarget->isAlive())
2836 return;
2838 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2839 return;
2841 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2843 uint32 maxPower = unitTarget->GetMaxPower(power);
2844 if(maxPower == 0)
2845 return;
2847 uint32 gain = damage * maxPower / 100;
2848 unitTarget->ModifyPower(power, gain);
2849 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, gain, power);
2852 void Spell::SendLoot(uint64 guid, LootType loottype)
2854 Player* player = (Player*)m_caster;
2855 if (!player)
2856 return;
2858 if (gameObjTarget)
2860 if (Script->GOHello(player, gameObjTarget))
2861 return;
2863 switch (gameObjTarget->GetGoType())
2865 case GAMEOBJECT_TYPE_DOOR:
2866 case GAMEOBJECT_TYPE_BUTTON:
2867 gameObjTarget->UseDoorOrButton();
2868 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2869 return;
2871 case GAMEOBJECT_TYPE_QUESTGIVER:
2872 // start or end quest
2873 player->PrepareQuestMenu(guid);
2874 player->SendPreparedQuest(guid);
2875 return;
2877 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2878 // triggering linked GO
2879 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2880 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2881 return;
2883 case GAMEOBJECT_TYPE_GOOBER:
2884 // goober_scripts can be triggered if the player don't have the quest
2885 if (gameObjTarget->GetGOInfo()->goober.eventId)
2887 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2888 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2891 // cast goober spell
2892 if (gameObjTarget->GetGOInfo()->goober.questId)
2893 ///Quest require to be active for GO using
2894 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2895 return;
2897 gameObjTarget->AddUniqueUse(player);
2898 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2900 //TODO? Objective counting called without spell check but with quest objective check
2901 // if send spell id then this line will duplicate to spell casting call (double counting)
2902 // So we or have this line and not required in quest_template have reqSpellIdN
2903 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2904 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2906 // triggering linked GO
2907 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2908 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2910 return;
2912 case GAMEOBJECT_TYPE_CHEST:
2913 // TODO: possible must be moved to loot release (in different from linked triggering)
2914 if (gameObjTarget->GetGOInfo()->chest.eventId)
2916 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2917 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2920 // triggering linked GO
2921 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2922 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2924 // Don't return, let loots been taken
2928 // Send loot
2929 player->SendLoot(guid, loottype);
2932 void Spell::EffectOpenLock(uint32 effIndex)
2934 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2936 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2937 return;
2940 Player* player = (Player*)m_caster;
2942 uint32 lockId = 0;
2943 uint64 guid = 0;
2945 // Get lockId
2946 if(gameObjTarget)
2948 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2949 // Arathi Basin banner opening !
2950 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2951 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2953 //CanUseBattleGroundObject() already called in CheckCast()
2954 // in battleground check
2955 if(BattleGround *bg = player->GetBattleGround())
2957 // check if it's correct bg
2958 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2959 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2960 return;
2963 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2965 //CanUseBattleGroundObject() already called in CheckCast()
2966 // in battleground check
2967 if(BattleGround *bg = player->GetBattleGround())
2969 if(bg->GetTypeID() == BATTLEGROUND_EY)
2970 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2971 return;
2974 lockId = gameObjTarget->GetLockId();
2975 guid = gameObjTarget->GetGUID();
2977 else if(itemTarget)
2979 lockId = itemTarget->GetProto()->LockID;
2980 guid = itemTarget->GetGUID();
2982 else
2984 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2985 return;
2988 SkillType skillId = SKILL_NONE;
2989 int32 reqSkillValue = 0;
2990 int32 skillValue;
2992 SpellCastResult res = CanOpenLock(effIndex,lockId,skillId,reqSkillValue,skillValue);
2993 if(res != SPELL_CAST_OK)
2995 SendCastResult(res);
2996 return;
2999 SendLoot(guid, LOOT_SKINNING);
3001 // not allow use skill grow at item base open
3002 if(!m_CastItem && skillId != SKILL_NONE)
3004 // update skill if really known
3005 if(uint32 pureSkillValue = player->GetPureSkillValue(skillId))
3007 if(gameObjTarget)
3009 // Allow one skill-up until respawned
3010 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
3011 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue) )
3012 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
3014 else if(itemTarget)
3016 // Do one skill-up
3017 player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue);
3023 void Spell::EffectSummonChangeItem(uint32 i)
3025 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3026 return;
3028 Player *player = (Player*)m_caster;
3030 // applied only to using item
3031 if(!m_CastItem)
3032 return;
3034 // ... only to item in own inventory/bank/equip_slot
3035 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
3036 return;
3038 uint32 newitemid = m_spellInfo->EffectItemType[i];
3039 if(!newitemid)
3040 return;
3042 uint16 pos = m_CastItem->GetPos();
3044 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
3045 if( !pNewItem )
3046 return;
3048 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
3050 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
3051 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
3054 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
3056 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3057 player->DurabilityLoss(pNewItem, loosePercent);
3060 if( player->IsInventoryPos( pos ) )
3062 ItemPosCountVec dest;
3063 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3064 if( msg == EQUIP_ERR_OK )
3066 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3068 // prevent crash at access and unexpected charges counting with item update queue corrupt
3069 if(m_CastItem==m_targets.getItemTarget())
3070 m_targets.setItemTarget(NULL);
3072 m_CastItem = NULL;
3074 player->StoreItem( dest, pNewItem, true);
3075 return;
3078 else if( player->IsBankPos ( pos ) )
3080 ItemPosCountVec dest;
3081 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3082 if( msg == EQUIP_ERR_OK )
3084 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3086 // prevent crash at access and unexpected charges counting with item update queue corrupt
3087 if(m_CastItem==m_targets.getItemTarget())
3088 m_targets.setItemTarget(NULL);
3090 m_CastItem = NULL;
3092 player->BankItem( dest, pNewItem, true);
3093 return;
3096 else if( player->IsEquipmentPos ( pos ) )
3098 uint16 dest;
3099 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3100 if( msg == EQUIP_ERR_OK )
3102 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3104 // prevent crash at access and unexpected charges counting with item update queue corrupt
3105 if(m_CastItem==m_targets.getItemTarget())
3106 m_targets.setItemTarget(NULL);
3108 m_CastItem = NULL;
3110 player->EquipItem( dest, pNewItem, true);
3111 player->AutoUnequipOffhandIfNeed();
3112 return;
3116 // fail
3117 delete pNewItem;
3120 void Spell::EffectOpenSecretSafe(uint32 i)
3122 EffectOpenLock(i); //no difference for now
3125 void Spell::EffectProficiency(uint32 /*i*/)
3127 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3128 return;
3129 Player *p_target = (Player*)unitTarget;
3131 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3132 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3134 p_target->AddWeaponProficiency(subClassMask);
3135 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3137 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3139 p_target->AddArmorProficiency(subClassMask);
3140 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3144 void Spell::EffectApplyAreaAura(uint32 i)
3146 if(!unitTarget)
3147 return;
3148 if(!unitTarget->isAlive())
3149 return;
3151 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3152 unitTarget->AddAura(Aur);
3155 void Spell::EffectSummonType(uint32 i)
3157 switch(m_spellInfo->EffectMiscValueB[i])
3159 case SUMMON_TYPE_GUARDIAN:
3160 case SUMMON_TYPE_POSESSED:
3161 case SUMMON_TYPE_POSESSED2:
3162 case SUMMON_TYPE_FORCE_OF_NATURE:
3163 case SUMMON_TYPE_GUARDIAN2:
3164 EffectSummonGuardian(i);
3165 break;
3166 case SUMMON_TYPE_WILD:
3167 EffectSummonWild(i);
3168 break;
3169 case SUMMON_TYPE_DEMON:
3170 EffectSummonDemon(i);
3171 break;
3172 case SUMMON_TYPE_SUMMON:
3173 EffectSummon(i);
3174 break;
3175 case SUMMON_TYPE_CRITTER:
3176 case SUMMON_TYPE_CRITTER2:
3177 case SUMMON_TYPE_CRITTER3:
3178 EffectSummonCritter(i);
3179 break;
3180 case SUMMON_TYPE_TOTEM_SLOT1:
3181 case SUMMON_TYPE_TOTEM_SLOT2:
3182 case SUMMON_TYPE_TOTEM_SLOT3:
3183 case SUMMON_TYPE_TOTEM_SLOT4:
3184 case SUMMON_TYPE_TOTEM:
3185 EffectSummonTotem(i);
3186 break;
3187 case SUMMON_TYPE_UNKNOWN1:
3188 case SUMMON_TYPE_UNKNOWN2:
3189 case SUMMON_TYPE_UNKNOWN3:
3190 case SUMMON_TYPE_UNKNOWN4:
3191 case SUMMON_TYPE_UNKNOWN5:
3192 break;
3193 default:
3194 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3195 break;
3199 void Spell::EffectSummon(uint32 i)
3201 if(m_caster->GetPetGUID())
3202 return;
3204 if(!unitTarget)
3205 return;
3206 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3207 if(!pet_entry)
3208 return;
3209 uint32 level = m_caster->getLevel();
3210 Pet* spawnCreature = new Pet(SUMMON_PET);
3212 if(m_caster->GetTypeId()==TYPEID_PLAYER && spawnCreature->LoadPetFromDB((Player*)m_caster,pet_entry))
3214 // set timer for unsummon
3215 int32 duration = GetSpellDuration(m_spellInfo);
3216 if(duration > 0)
3217 spawnCreature->SetDuration(duration);
3219 return;
3222 Map *map = m_caster->GetMap();
3223 uint32 pet_number = objmgr.GeneratePetNumber();
3224 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_caster->GetPhaseMask(),
3225 m_spellInfo->EffectMiscValue[i], pet_number))
3227 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3228 delete spawnCreature;
3229 return;
3232 // Summon in dest location
3233 float x,y,z;
3234 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3236 x = m_targets.m_destX;
3237 y = m_targets.m_destY;
3238 z = m_targets.m_destZ;
3240 else
3241 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3243 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3245 if(!spawnCreature->IsPositionValid())
3247 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
3248 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3249 delete spawnCreature;
3250 return;
3253 // set timer for unsummon
3254 int32 duration = GetSpellDuration(m_spellInfo);
3255 if(duration > 0)
3256 spawnCreature->SetDuration(duration);
3258 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3259 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS, 0);
3260 spawnCreature->setPowerType(POWER_MANA);
3261 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, m_caster->getFaction());
3262 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
3263 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
3264 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
3265 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0);
3266 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
3267 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
3268 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3269 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3271 spawnCreature->InitStatsForLevel(level);
3273 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3275 spawnCreature->AIM_Initialize();
3276 spawnCreature->InitPetCreateSpells();
3277 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3278 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3280 std::string name = m_caster->GetName();
3281 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3282 spawnCreature->SetName( name );
3284 map->Add((Creature*)spawnCreature);
3286 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3288 m_caster->SetPet(spawnCreature);
3289 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3290 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3291 ((Player*)m_caster)->PetSpellInitialize();
3295 void Spell::EffectLearnSpell(uint32 i)
3297 if(!unitTarget)
3298 return;
3300 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3302 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3303 EffectLearnPetSpell(i);
3305 return;
3308 Player *player = (Player*)unitTarget;
3310 uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
3311 player->learnSpell(spellToLearn,false);
3313 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3316 void Spell::EffectDispel(uint32 i)
3318 if(!unitTarget)
3319 return;
3321 // Fill possible dispell list
3322 std::vector <Aura *> dispel_list;
3324 // Create dispel mask by dispel type
3325 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3326 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3327 Unit::AuraMap const& auras = unitTarget->GetAuras();
3328 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3330 Aura *aur = (*itr).second;
3331 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3333 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3335 bool positive = true;
3336 if (!aur->IsPositive())
3337 positive = false;
3338 else
3339 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3341 // do not remove positive auras if friendly target
3342 // negative auras if non-friendly target
3343 if(positive == unitTarget->IsFriendlyTo(m_caster))
3344 continue;
3346 // Add aura to dispel list
3347 dispel_list.push_back(aur);
3350 // Ok if exist some buffs for dispel try dispel it
3351 if (!dispel_list.empty())
3353 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3354 std::list < uint32 > fail_list; // spell_id
3355 int32 list_size = dispel_list.size();
3356 // Dispell N = damage buffs (or while exist buffs for dispel)
3357 for (int32 count=0; count < damage && list_size > 0; ++count)
3359 // Random select buff for dispel
3360 Aura *aur = dispel_list[urand(0, list_size-1)];
3362 SpellEntry const* spellInfo = aur->GetSpellProto();
3363 // Base dispel chance
3364 // TODO: possible chance depend from spell level??
3365 int32 miss_chance = 0;
3366 // Apply dispel mod from aura caster
3367 if (Unit *caster = aur->GetCaster())
3369 if ( Player* modOwner = caster->GetSpellModOwner() )
3370 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3372 // Try dispel
3373 if (roll_chance_i(miss_chance))
3374 fail_list.push_back(aur->GetId());
3375 else
3376 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3377 // Remove buff from list for prevent doubles
3378 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3380 Aura *dispeled = *j;
3381 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3383 j = dispel_list.erase(j);
3384 --list_size;
3386 else
3387 ++j;
3390 // Send success log and really remove auras
3391 if (!success_list.empty())
3393 int32 count = success_list.size();
3394 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3395 data.append(unitTarget->GetPackGUID()); // Victim GUID
3396 data.append(m_caster->GetPackGUID()); // Caster GUID
3397 data << uint32(m_spellInfo->Id); // Dispell spell id
3398 data << uint8(0); // not used
3399 data << uint32(count); // count
3400 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3402 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3403 data << uint32(spellInfo->Id); // Spell Id
3404 data << uint8(0); // 0 - dispeled !=0 cleansed
3405 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3407 m_caster->SendMessageToSet(&data, true);
3409 // On succes dispel
3410 // Devour Magic
3411 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
3413 uint32 heal_spell = 0;
3414 switch (m_spellInfo->Id)
3416 case 19505: heal_spell = 19658; break;
3417 case 19731: heal_spell = 19732; break;
3418 case 19734: heal_spell = 19733; break;
3419 case 19736: heal_spell = 19735; break;
3420 case 27276: heal_spell = 27278; break;
3421 case 27277: heal_spell = 27279; break;
3422 default:
3423 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3424 break;
3426 if (heal_spell)
3427 m_caster->CastSpell(m_caster, heal_spell, true);
3430 // Send fail log to client
3431 if (!fail_list.empty())
3433 // Failed to dispell
3434 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3435 data << uint64(m_caster->GetGUID()); // Caster GUID
3436 data << uint64(unitTarget->GetGUID()); // Victim GUID
3437 data << uint32(m_spellInfo->Id); // Dispell spell id
3438 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3439 data << uint32(*j); // Spell Id
3440 m_caster->SendMessageToSet(&data, true);
3445 void Spell::EffectDualWield(uint32 /*i*/)
3447 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
3448 ((Player*)unitTarget)->SetCanDualWield(true);
3451 void Spell::EffectPull(uint32 /*i*/)
3453 // TODO: create a proper pull towards distract spell center for distract
3454 sLog.outDebug("WORLD: Spell Effect DUMMY");
3457 void Spell::EffectDistract(uint32 /*i*/)
3459 // Check for possible target
3460 if (!unitTarget || unitTarget->isInCombat())
3461 return;
3463 // target must be OK to do this
3464 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3465 return;
3467 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3469 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3471 // For players just turn them
3472 WorldPacket data;
3473 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3474 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3475 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3477 else
3479 // Set creature Distracted, Stop it, And turn it
3480 unitTarget->SetOrientation(angle);
3481 unitTarget->StopMoving();
3482 unitTarget->GetMotionMaster()->MoveDistract(damage*IN_MILISECONDS);
3486 void Spell::EffectPickPocket(uint32 /*i*/)
3488 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3489 return;
3491 // victim must be creature and attackable
3492 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3493 return;
3495 // victim have to be alive and humanoid or undead
3496 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3498 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3500 if (chance > irand(0, 19))
3502 // Stealing successful
3503 //sLog.outDebug("Sending loot from pickpocket");
3504 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3506 else
3508 // Reveal action + get attack
3509 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3510 if (((Creature*)unitTarget)->AI())
3511 ((Creature*)unitTarget)->AI()->AttackedBy(m_caster);
3516 void Spell::EffectAddFarsight(uint32 i)
3518 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3519 int32 duration = GetSpellDuration(m_spellInfo);
3520 DynamicObject* dynObj = new DynamicObject;
3521 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))
3523 delete dynObj;
3524 return;
3526 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3527 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3528 m_caster->AddDynObject(dynObj);
3529 dynObj->GetMap()->Add(dynObj);
3530 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3531 ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID());
3534 void Spell::EffectSummonWild(uint32 i)
3536 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3537 if(!creature_entry)
3538 return;
3540 uint32 level = m_caster->getLevel();
3542 // level of creature summoned using engineering item based at engineering skill level
3543 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3545 ItemPrototype const *proto = m_CastItem->GetProto();
3546 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3548 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3549 if(skill202)
3551 level = skill202/5;
3556 // select center of summon position
3557 float center_x = m_targets.m_destX;
3558 float center_y = m_targets.m_destY;
3559 float center_z = m_targets.m_destZ;
3561 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3563 int32 amount = damage > 0 ? damage : 1;
3565 for(int32 count = 0; count < amount; ++count)
3567 float px, py, pz;
3568 // If dest location if present
3569 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3571 // Summon 1 unit in dest location
3572 if (count == 0)
3574 px = m_targets.m_destX;
3575 py = m_targets.m_destY;
3576 pz = m_targets.m_destZ;
3578 // Summon in random point all other units if location present
3579 else
3580 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3582 // Summon if dest location not present near caster
3583 else
3584 m_caster->GetClosePoint(px,py,pz,3.0f);
3586 int32 duration = GetSpellDuration(m_spellInfo);
3588 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3590 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3594 void Spell::EffectSummonGuardian(uint32 i)
3596 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3597 if(!pet_entry)
3598 return;
3600 // Jewelery statue case (totem like)
3601 if(m_spellInfo->SpellIconID==2056)
3603 EffectSummonTotem(i);
3604 return;
3607 // set timer for unsummon
3608 int32 duration = GetSpellDuration(m_spellInfo);
3610 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3611 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3612 // so this code hack in fact
3613 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3614 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3615 return; // find old guardian, ignore summon
3617 // in another case summon new
3618 uint32 level = m_caster->getLevel();
3620 // level of pet summoned using engineering item based at engineering skill level
3621 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3623 ItemPrototype const *proto = m_CastItem->GetProto();
3624 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3626 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3627 if(skill202)
3629 level = skill202/5;
3634 // select center of summon position
3635 float center_x = m_targets.m_destX;
3636 float center_y = m_targets.m_destY;
3637 float center_z = m_targets.m_destZ;
3639 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3641 int32 amount = damage > 0 ? damage : 1;
3643 for(int32 count = 0; count < amount; ++count)
3645 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3647 Map *map = m_caster->GetMap();
3648 uint32 pet_number = objmgr.GeneratePetNumber();
3649 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_caster->GetPhaseMask(),
3650 m_spellInfo->EffectMiscValue[i], pet_number))
3652 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3653 delete spawnCreature;
3654 return;
3657 float px, py, pz;
3658 // If dest location if present
3659 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3661 // Summon 1 unit in dest location
3662 if (count == 0)
3664 px = m_targets.m_destX;
3665 py = m_targets.m_destY;
3666 pz = m_targets.m_destZ;
3668 // Summon in random point all other units if location present
3669 else
3670 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3672 // Summon if dest location not present near caster
3673 else
3674 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3676 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3678 if(!spawnCreature->IsPositionValid())
3680 sLog.outError("Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %f Y: %f)",
3681 spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3682 delete spawnCreature;
3683 return;
3686 if(duration > 0)
3687 spawnCreature->SetDuration(duration);
3689 spawnCreature->SetOwnerGUID(m_caster->GetGUID());
3690 spawnCreature->setPowerType(POWER_MANA);
3691 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3692 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3693 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3694 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3695 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3696 spawnCreature->SetCreatorGUID(m_caster->GetGUID());
3697 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3699 spawnCreature->InitStatsForLevel(level);
3700 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3702 spawnCreature->AIM_Initialize();
3704 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3705 ((Player*)m_caster)->AddGuardian(spawnCreature);
3707 map->Add((Creature*)spawnCreature);
3711 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3713 if(!unitTarget)
3714 return;
3716 if(unitTarget->isInFlight())
3717 return;
3719 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3721 float fx,fy,fz;
3722 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3724 unitTarget->NearTeleportTo(fx,fy,fz,-m_caster->GetOrientation(),unitTarget==m_caster);
3727 void Spell::EffectLearnSkill(uint32 i)
3729 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3730 return;
3732 if(damage < 0)
3733 return;
3735 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3736 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3737 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3740 void Spell::EffectAddHonor(uint32 /*i*/)
3742 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3743 return;
3745 // not scale value for item based reward (/10 value expected)
3746 if(m_CastItem)
3748 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage/10);
3749 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %d honor points (item %u) for player: %u", m_spellInfo->Id, damage/10, m_CastItem->GetEntry(),((Player*)unitTarget)->GetGUIDLow());
3750 return;
3753 // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80
3754 if( damage <= 50)
3756 uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage);
3757 ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward);
3758 sLog.outDebug("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (scale) to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow());
3760 else
3762 //maybe we have correct honor_gain in damage already
3763 ((Player*)unitTarget)->RewardHonor(NULL, 1, damage);
3764 sLog.outError("SpellEffect::AddHonor (spell_id %u) rewards %u honor points (non scale) for player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow());
3768 void Spell::EffectTradeSkill(uint32 /*i*/)
3770 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3771 return;
3772 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3773 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3774 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3777 void Spell::EffectEnchantItemPerm(uint32 effect_idx)
3779 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3780 return;
3781 if (!itemTarget)
3782 return;
3784 Player* p_caster = (Player*)m_caster;
3786 // not grow at item use at item case
3787 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3789 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3790 if (!enchant_id)
3791 return;
3793 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3794 if(!pEnchant)
3795 return;
3797 // item can be in trade slot and have owner diff. from caster
3798 Player* item_owner = itemTarget->GetOwner();
3799 if(!item_owner)
3800 return;
3802 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3804 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3805 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3806 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3807 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3810 // remove old enchanting before applying new if equipped
3811 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3813 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3815 // add new enchanting if equipped
3816 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3819 void Spell::EffectEnchantItemPrismatic(uint32 effect_idx)
3821 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3822 return;
3823 if (!itemTarget)
3824 return;
3826 Player* p_caster = (Player*)m_caster;
3828 uint32 enchant_id = m_spellInfo->EffectMiscValue[effect_idx];
3829 if (!enchant_id)
3830 return;
3832 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3833 if(!pEnchant)
3834 return;
3836 // support only enchantings with add socket in this slot
3838 bool add_socket = false;
3839 for(int i = 0; i < 3; ++i)
3841 if(pEnchant->type[i]==ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET)
3843 add_socket = true;
3844 break;
3847 if(!add_socket)
3849 sLog.outError("Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (u), not suppoted yet.",
3850 m_spellInfo->Id,SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC,ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET);
3851 return;
3855 // item can be in trade slot and have owner diff. from caster
3856 Player* item_owner = itemTarget->GetOwner();
3857 if(!item_owner)
3858 return;
3860 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3862 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3863 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3864 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3865 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3868 // remove old enchanting before applying new if equipped
3869 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,false);
3871 itemTarget->SetEnchantment(PRISMATIC_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3873 // add new enchanting if equipped
3874 item_owner->ApplyEnchantment(itemTarget,PRISMATIC_ENCHANTMENT_SLOT,true);
3877 void Spell::EffectEnchantItemTmp(uint32 i)
3879 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3880 return;
3882 Player* p_caster = (Player*)m_caster;
3884 if(!itemTarget)
3885 return;
3887 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3889 // Shaman Rockbiter Weapon
3890 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3892 int32 enchnting_damage = m_currentBasePoints[1]+1;
3894 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3895 // with already applied percent bonus from Elemental Weapons talent
3896 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3897 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3898 switch(enchnting_damage)
3900 // Rank 1
3901 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3902 // Rank 2
3903 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3904 case 5: enchant_id = 3025; break; // 20%
3905 // Rank 3
3906 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3907 case 7: enchant_id = 3027; break; // 20%
3908 // Rank 4
3909 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3910 case 10: enchant_id = 503; break; // 14%
3911 case 11: enchant_id = 3031; break; // 20%
3912 // Rank 5
3913 case 15: enchant_id = 3035; break; // 0%
3914 case 16: enchant_id = 1663; break; // 7%
3915 case 17: enchant_id = 3033; break; // 14%
3916 case 18: enchant_id = 3034; break; // 20%
3917 // Rank 6
3918 case 28: enchant_id = 3038; break; // 0%
3919 case 29: enchant_id = 683; break; // 7%
3920 case 31: enchant_id = 3036; break; // 14%
3921 case 33: enchant_id = 3037; break; // 20%
3922 // Rank 7
3923 case 40: enchant_id = 3041; break; // 0%
3924 case 42: enchant_id = 1664; break; // 7%
3925 case 45: enchant_id = 3039; break; // 14%
3926 case 48: enchant_id = 3040; break; // 20%
3927 // Rank 8
3928 case 49: enchant_id = 3044; break; // 0%
3929 case 52: enchant_id = 2632; break; // 7%
3930 case 55: enchant_id = 3042; break; // 14%
3931 case 58: enchant_id = 3043; break; // 20%
3932 // Rank 9
3933 case 62: enchant_id = 2633; break; // 0%
3934 case 66: enchant_id = 3018; break; // 7%
3935 case 70: enchant_id = 3019; break; // 14%
3936 case 74: enchant_id = 3020; break; // 20%
3937 default:
3938 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3939 return;
3943 if (!enchant_id)
3945 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3946 return;
3949 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3950 if(!pEnchant)
3952 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3953 return;
3956 // select enchantment duration
3957 uint32 duration;
3959 // rogue family enchantments exception by duration
3960 if(m_spellInfo->Id==38615)
3961 duration = 1800; // 30 mins
3962 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3963 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3964 duration = 3600; // 1 hour
3965 // shaman family enchantments
3966 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3967 duration = 1800; // 30 mins
3968 // other cases with this SpellVisual already selected
3969 else if(m_spellInfo->SpellVisual[0]==215)
3970 duration = 1800; // 30 mins
3971 // some fishing pole bonuses
3972 else if(m_spellInfo->SpellVisual[0]==563)
3973 duration = 600; // 10 mins
3974 // shaman rockbiter enchantments
3975 else if(m_spellInfo->SpellVisual[0]==0)
3976 duration = 1800; // 30 mins
3977 else if(m_spellInfo->Id==29702)
3978 duration = 300; // 5 mins
3979 else if(m_spellInfo->Id==37360)
3980 duration = 300; // 5 mins
3981 // default case
3982 else
3983 duration = 3600; // 1 hour
3985 // item can be in trade slot and have owner diff. from caster
3986 Player* item_owner = itemTarget->GetOwner();
3987 if(!item_owner)
3988 return;
3990 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3992 sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3993 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3994 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3995 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3998 // remove old enchanting before applying new if equipped
3999 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
4001 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
4003 // add new enchanting if equipped
4004 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
4007 void Spell::EffectTameCreature(uint32 /*i*/)
4009 if(m_caster->GetPetGUID())
4010 return;
4012 if(!unitTarget)
4013 return;
4015 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
4016 return;
4018 Creature* creatureTarget = (Creature*)unitTarget;
4020 if(creatureTarget->isPet())
4021 return;
4023 if(m_caster->getClass() != CLASS_HUNTER)
4024 return;
4026 // cast finish successfully
4027 //SendChannelUpdate(0);
4028 finish();
4030 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
4032 // kill original creature
4033 creatureTarget->setDeathState(JUST_DIED);
4034 creatureTarget->RemoveCorpse();
4035 creatureTarget->SetHealth(0); // just for nice GM-mode view
4037 uint32 level = (creatureTarget->getLevel() < (m_caster->getLevel() - 5)) ? (m_caster->getLevel() - 5) : creatureTarget->getLevel();
4039 // prepare visual effect for levelup
4040 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1);
4042 // add to world
4043 pet->GetMap()->Add((Creature*)pet);
4045 // visual effect for levelup
4046 pet->SetUInt32Value(UNIT_FIELD_LEVEL, level);
4048 // caster have pet now
4049 m_caster->SetPet(pet);
4051 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4053 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4054 ((Player*)m_caster)->PetSpellInitialize();
4058 void Spell::EffectSummonPet(uint32 i)
4060 uint32 petentry = m_spellInfo->EffectMiscValue[i];
4062 Pet *OldSummon = m_caster->GetPet();
4064 // if pet requested type already exist
4065 if( OldSummon )
4067 if(petentry == 0 || OldSummon->GetEntry() == petentry)
4069 // pet in corpse state can't be summoned
4070 if( OldSummon->isDead() )
4071 return;
4073 OldSummon->GetMap()->Remove((Creature*)OldSummon,false);
4074 OldSummon->SetMapId(m_caster->GetMapId());
4076 float px, py, pz;
4077 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
4079 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
4080 m_caster->GetMap()->Add((Creature*)OldSummon);
4082 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
4084 ((Player*)m_caster)->PetSpellInitialize();
4086 return;
4089 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4090 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
4091 else
4092 return;
4095 Pet* NewSummon = new Pet;
4097 // petentry==0 for hunter "call pet" (current pet summoned if any)
4098 if(m_caster->GetTypeId() == TYPEID_PLAYER && NewSummon->LoadPetFromDB((Player*)m_caster,petentry))
4100 if(NewSummon->getPetType()==SUMMON_PET)
4102 // Remove Demonic Sacrifice auras (known pet)
4103 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4104 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4106 if((*itr)->GetModifier()->m_miscvalue==2228)
4108 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4109 itr = auraClassScripts.begin();
4111 else
4112 ++itr;
4116 return;
4119 // not error in case fail hunter call pet
4120 if(!petentry)
4122 delete NewSummon;
4123 return;
4126 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
4128 if(!cInfo)
4130 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
4131 delete NewSummon;
4132 return;
4135 Map *map = m_caster->GetMap();
4136 uint32 pet_number = objmgr.GeneratePetNumber();
4137 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
4138 petentry, pet_number))
4140 delete NewSummon;
4141 return;
4144 float px, py, pz;
4145 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4147 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4149 if(!NewSummon->IsPositionValid())
4151 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
4152 NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4153 delete NewSummon;
4154 return;
4157 uint32 petlevel = m_caster->getLevel();
4158 NewSummon->setPetType(SUMMON_PET);
4160 uint32 faction = m_caster->getFaction();
4161 if(m_caster->GetTypeId() == TYPEID_UNIT)
4163 if ( ((Creature*)m_caster)->isTotem() )
4164 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4165 else
4166 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4169 NewSummon->SetOwnerGUID(m_caster->GetGUID());
4170 NewSummon->SetCreatorGUID(m_caster->GetGUID());
4171 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS, 0);
4172 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4173 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0, 2048);
4174 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
4175 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
4176 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0);
4177 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, 1000);
4178 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4180 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4181 // this enables pet details window (Shift+P)
4183 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4184 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4185 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4187 NewSummon->InitStatsForLevel(petlevel);
4188 NewSummon->InitPetCreateSpells();
4189 NewSummon->InitTalentForLevel();
4191 if(NewSummon->getPetType()==SUMMON_PET)
4193 // Remove Demonic Sacrifice auras (new pet)
4194 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4195 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4197 if((*itr)->GetModifier()->m_miscvalue==2228)
4199 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4200 itr = auraClassScripts.begin();
4202 else
4203 ++itr;
4206 // generate new name for summon pet
4207 std::string new_name=objmgr.GeneratePetName(petentry);
4208 if(!new_name.empty())
4209 NewSummon->SetName(new_name);
4211 else if(NewSummon->getPetType()==HUNTER_PET)
4212 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4214 NewSummon->AIM_Initialize();
4215 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4216 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4218 map->Add((Creature*)NewSummon);
4220 m_caster->SetPet(NewSummon);
4221 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4223 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4225 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4226 ((Player*)m_caster)->PetSpellInitialize();
4230 void Spell::EffectLearnPetSpell(uint32 i)
4232 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4233 return;
4235 Player *_player = (Player*)m_caster;
4237 Pet *pet = _player->GetPet();
4238 if(!pet)
4239 return;
4240 if(!pet->isAlive())
4241 return;
4243 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4244 if(!learn_spellproto)
4245 return;
4247 pet->learnSpell(learn_spellproto->Id);
4249 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4250 _player->PetSpellInitialize();
4253 void Spell::EffectTaunt(uint32 /*i*/)
4255 // this effect use before aura Taunt apply for prevent taunt already attacking target
4256 // for spell as marked "non effective at already attacking target"
4257 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4259 if(unitTarget->getVictim()==m_caster)
4261 SendCastResult(SPELL_FAILED_DONT_REPORT);
4262 return;
4266 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4267 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4268 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4271 void Spell::EffectWeaponDmg(uint32 i)
4273 if(!unitTarget)
4274 return;
4275 if(!unitTarget->isAlive())
4276 return;
4278 // multiple weapon dmg effect workaround
4279 // execute only the last weapon damage
4280 // and handle all effects at once
4281 for (int j = 0; j < 3; j++)
4283 switch(m_spellInfo->Effect[j])
4285 case SPELL_EFFECT_WEAPON_DAMAGE:
4286 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4287 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4288 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4289 if (j < i) // we must calculate only at last weapon effect
4290 return;
4291 break;
4295 // some spell specific modifiers
4296 bool spellBonusNeedWeaponDamagePercentMod = false; // if set applied weapon damage percent mode to spell bonus
4298 float weaponDamagePercentMod = 1.0f; // applied to weapon damage and to fixed effect damage bonus
4299 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4300 bool normalized = false;
4302 int32 spell_bonus = 0; // bonus specific for spell
4303 switch(m_spellInfo->SpellFamilyName)
4305 case SPELLFAMILY_WARRIOR:
4307 // Whirlwind, single only spell with 2 weapon white damage apply if have
4308 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4310 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4311 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4313 // Devastate bonus and sunder armor refresh
4314 else if(m_spellInfo->SpellVisual[0] == 671 && m_spellInfo->SpellIconID == 1508)
4316 uint32 stack = 0;
4317 // Need refresh all Sunder Armor auras from this caster
4318 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4319 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4321 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
4322 if( spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR &&
4323 spellInfo->SpellFamilyFlags & 0x0000000000004000LL &&
4324 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
4326 (*itr).second->RefreshAura();
4327 stack = (*itr).second->GetStackAmount();
4330 if (stack)
4331 spell_bonus += stack * CalculateDamage(2, unitTarget);
4333 break;
4335 case SPELLFAMILY_ROGUE:
4337 // Mutilate (for each hand)
4338 if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4340 bool found = false;
4341 // fast check
4342 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4343 found = true;
4344 // full aura scan
4345 else
4347 Unit::AuraMap const& auras = unitTarget->GetAuras();
4348 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4350 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4352 found = true;
4353 break;
4358 if(found)
4359 totalDamagePercentMod *= 1.2f; // 120% if poisoned
4361 break;
4363 case SPELLFAMILY_PALADIN:
4365 // Seal of Command - receive benefit from Spell Damage and Healing
4366 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4368 spellBonusNeedWeaponDamagePercentMod = true;// apply weaponDamagePercentMod to spell_bonus (and then to all bonus, fixes and weapon already have applied)
4369 spell_bonus += int32(0.23f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4370 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4372 break;
4374 case SPELLFAMILY_SHAMAN:
4376 // Skyshatter Harness item set bonus
4377 // Stormstrike
4378 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4380 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4381 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4383 // Stormstrike AP Buff
4384 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4386 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4387 break;
4394 int32 fixed_bonus = 0;
4395 for (int j = 0; j < 3; j++)
4397 switch(m_spellInfo->Effect[j])
4399 case SPELL_EFFECT_WEAPON_DAMAGE:
4400 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4401 fixed_bonus += CalculateDamage(j,unitTarget);
4402 break;
4403 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4404 fixed_bonus += CalculateDamage(j,unitTarget);
4405 normalized = true;
4406 break;
4407 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4408 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4410 // applied only to prev.effects fixed damage
4411 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4412 break;
4413 default:
4414 break; // not weapon damage effect, just skip
4418 // apply weaponDamagePercentMod to spell bonus also
4419 if(spellBonusNeedWeaponDamagePercentMod)
4420 spell_bonus = int32(spell_bonus*weaponDamagePercentMod);
4422 // non-weapon damage
4423 int32 bonus = spell_bonus + fixed_bonus;
4425 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4426 if(bonus)
4428 UnitMods unitMod;
4429 switch(m_attackType)
4431 default:
4432 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4433 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4434 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4437 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4438 bonus = int32(bonus*weapon_total_pct);
4441 // + weapon damage with applied weapon% dmg to base weapon damage in call
4442 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4444 // total damage
4445 bonus = int32(bonus*totalDamagePercentMod);
4447 // prevent negative damage
4448 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4450 // Add melee damage bonuses (also check for negative)
4451 m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
4452 m_damage+= eff_damage;
4454 // Hemorrhage
4455 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4457 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4458 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4461 // Mangle (Cat): CP
4462 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4464 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4465 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4468 // take ammo
4469 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4471 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4473 // wands don't have ammo
4474 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4475 return;
4477 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4479 if(pItem->GetMaxStackCount()==1)
4481 // decrease durability for non-stackable throw weapon
4482 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4484 else
4486 // decrease items amount for stackable throw weapon
4487 uint32 count = 1;
4488 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4491 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4492 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4496 void Spell::EffectThreat(uint32 /*i*/)
4498 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4499 return;
4501 if(!unitTarget->CanHaveThreatList())
4502 return;
4504 unitTarget->AddThreat(m_caster, float(damage));
4507 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4509 if(!unitTarget)
4510 return;
4511 if(!unitTarget->isAlive())
4512 return;
4514 uint32 heal = m_caster->GetMaxHealth();
4516 m_healing+=heal;
4519 void Spell::EffectInterruptCast(uint32 /*i*/)
4521 if(!unitTarget)
4522 return;
4523 if(!unitTarget->isAlive())
4524 return;
4526 // TODO: not all spells that used this effect apply cooldown at school spells
4527 // also exist case: apply cooldown to interrupted cast only and to all spells
4528 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4530 if (unitTarget->m_currentSpells[i])
4532 // check if we can interrupt spell
4533 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4535 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4536 unitTarget->InterruptSpell(i,false);
4542 void Spell::EffectSummonObjectWild(uint32 i)
4544 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4546 GameObject* pGameObj = new GameObject;
4548 WorldObject* target = focusObject;
4549 if( !target )
4550 target = m_caster;
4552 float x,y,z;
4553 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4555 x = m_targets.m_destX;
4556 y = m_targets.m_destY;
4557 z = m_targets.m_destZ;
4559 else
4560 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4562 Map *map = target->GetMap();
4564 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4565 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, 1))
4567 delete pGameObj;
4568 return;
4571 int32 duration = GetSpellDuration(m_spellInfo);
4572 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4573 pGameObj->SetSpellId(m_spellInfo->Id);
4575 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4576 m_caster->AddGameObject(pGameObj);
4577 map->Add(pGameObj);
4579 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4581 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4583 Player *pl = (Player*)m_caster;
4584 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4585 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4587 uint32 team = ALLIANCE;
4589 if(pl->GetTeam() == team)
4590 team = HORDE;
4592 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4597 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4599 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4601 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4602 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4604 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4609 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4611 GameObject* linkedGO = new GameObject;
4612 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4613 m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, 1))
4615 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
4616 linkedGO->SetSpellId(m_spellInfo->Id);
4618 m_caster->AddGameObject(linkedGO);
4619 map->Add(linkedGO);
4621 else
4623 delete linkedGO;
4624 linkedGO = NULL;
4625 return;
4630 void Spell::EffectScriptEffect(uint32 effIndex)
4632 // TODO: we must implement hunter pet summon at login there (spell 6962)
4634 switch(m_spellInfo->SpellFamilyName)
4636 case SPELLFAMILY_GENERIC:
4638 switch(m_spellInfo->Id)
4640 // PX-238 Winter Wondervolt TRAP
4641 case 26275:
4643 uint32 spells[4] = { 26272, 26157, 26273, 26274 };
4645 // check presence
4646 for(int j = 0; j < 4; ++j)
4647 if(unitTarget->HasAura(spells[j],0))
4648 return;
4650 // select spell
4651 uint32 iTmpSpellId = spells[urand(0,3)];
4653 // cast
4654 unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
4655 return;
4657 // Bending Shinbone
4658 case 8856:
4660 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4661 return;
4663 uint32 spell_id = 0;
4664 switch(urand(1,5))
4666 case 1: spell_id = 8854; break;
4667 default: spell_id = 8855; break;
4670 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4671 return;
4673 // Brittle Armor - need remove one 24575 Brittle Armor aura
4674 case 24590:
4675 unitTarget->RemoveSingleSpellAurasFromStack(24575);
4676 return;
4677 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4678 case 26465:
4679 unitTarget->RemoveSingleSpellAurasFromStack(26464);
4680 return;
4681 // Orb teleport spells
4682 case 25140:
4683 case 25143:
4684 case 25650:
4685 case 25652:
4686 case 29128:
4687 case 29129:
4688 case 35376:
4689 case 35727:
4691 if(!unitTarget)
4692 return;
4694 uint32 spellid;
4695 switch(m_spellInfo->Id)
4697 case 25140: spellid = 32571; break;
4698 case 25143: spellid = 32572; break;
4699 case 25650: spellid = 30140; break;
4700 case 25652: spellid = 30141; break;
4701 case 29128: spellid = 32568; break;
4702 case 29129: spellid = 32569; break;
4703 case 35376: spellid = 25649; break;
4704 case 35727: spellid = 35730; break;
4705 default:
4706 return;
4709 unitTarget->CastSpell(unitTarget,spellid,false);
4710 return;
4712 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4713 case 22539:
4714 case 22972:
4715 case 22975:
4716 case 22976:
4717 case 22977:
4718 case 22978:
4719 case 22979:
4720 case 22980:
4721 case 22981:
4722 case 22982:
4723 case 22983:
4724 case 22984:
4725 case 22985:
4727 if(!unitTarget || !unitTarget->isAlive())
4728 return;
4730 // Onyxia Scale Cloak
4731 if(unitTarget->GetDummyAura(22683))
4732 return;
4734 // Shadow Flame
4735 m_caster->CastSpell(unitTarget, 22682, true);
4736 return;
4738 // Summon Black Qiraji Battle Tank
4739 case 26656:
4741 if(!unitTarget)
4742 return;
4744 // Prevent stacking of mounts
4745 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4747 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4748 if (unitTarget->GetAreaId() == 3428)
4749 unitTarget->CastSpell(unitTarget, 25863, false);
4750 else
4751 unitTarget->CastSpell(unitTarget, 26655, false);
4752 return;
4754 // Piccolo of the Flaming Fire
4755 case 17512:
4757 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4758 return;
4759 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4760 return;
4762 // Escape artist
4763 case 20589:
4765 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4766 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
4767 return;
4769 // Mirren's Drinking Hat
4770 case 29830:
4772 uint32 item = 0;
4773 switch ( urand(1,6) )
4775 case 1:case 2:case 3:
4776 item = 23584;break; // Loch Modan Lager
4777 case 4:case 5:
4778 item = 23585;break; // Stouthammer Lite
4779 case 6:
4780 item = 23586;break; // Aerie Peak Pale Ale
4782 if (item)
4783 DoCreateItem(effIndex,item);
4784 break;
4786 // Improved Sprint
4787 case 30918:
4789 // Removes snares and roots.
4790 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4791 Unit::AuraMap& Auras = unitTarget->GetAuras();
4792 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4794 next = iter;
4795 ++next;
4796 Aura *aur = iter->second;
4797 if (!aur->IsPositive()) //only remove negative spells
4799 // check for mechanic mask
4800 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4802 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4803 if(Auras.empty())
4804 break;
4805 else
4806 next = Auras.begin();
4810 break;
4812 // Flame Crash
4813 case 41126:
4815 if(!unitTarget)
4816 return;
4818 unitTarget->CastSpell(unitTarget, 41131, true);
4819 break;
4821 // Force Cast - Portal Effect: Sunwell Isle
4822 case 44876:
4824 if(!unitTarget)
4825 return;
4827 unitTarget->CastSpell(unitTarget, 44870, true);
4828 break;
4830 // Goblin Weather Machine
4831 case 46203:
4833 if(!unitTarget)
4834 return;
4836 uint32 spellId;
4837 switch(rand()%4)
4839 case 0: spellId = 46740; break;
4840 case 1: spellId = 46739; break;
4841 case 2: spellId = 46738; break;
4842 case 3: spellId = 46736; break;
4844 unitTarget->CastSpell(unitTarget, spellId, true);
4845 break;
4847 //5,000 Gold
4848 case 46642:
4850 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4851 return;
4853 ((Player*)unitTarget)->ModifyMoney(50000000);
4855 break;
4857 // Emblazon Runeblade
4858 case 51770:
4860 if(!unitTarget)
4861 return;
4863 unitTarget->CastSpell(unitTarget,51771,false);
4864 break;
4866 // Death Gate
4867 case 52751:
4869 if(!unitTarget || unitTarget->getClass() != CLASS_DEATH_KNIGHT)
4870 return;
4871 // triggered spell is stored in m_spellInfo->EffectBasePoints[0]
4872 unitTarget->CastSpell(unitTarget, damage, false);
4873 break;
4875 case 58418: // Portal to Orgrimmar
4876 case 58420: // Portal to Stormwind
4878 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || effIndex!=0)
4879 return;
4881 uint32 spellID = m_spellInfo->CalculateSimpleValue(0);
4882 uint32 questID = m_spellInfo->CalculateSimpleValue(1);
4884 if( ((Player*)unitTarget)->GetQuestStatus(questID) == QUEST_STATUS_COMPLETE && !((Player*)unitTarget)->GetQuestRewardStatus (questID) )
4885 unitTarget->CastSpell(unitTarget, spellID, true);
4887 return;
4889 // random spell learn instead placeholder
4890 case 60893: // Northrend Alchemy Research
4891 case 61177: // Northrend Inscription Research
4892 case 61288: // Minor Inscription Research
4893 case 61756: // Northrend Inscription Research (FAST QA VERSION)
4895 if(!IsExplicitDiscoverySpell(m_spellInfo))
4897 sLog.outError("Wrong explicit discovery spell %u structure, or outdated...",m_spellInfo->Id);
4898 return;
4901 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
4902 return;
4903 Player* player = (Player*)m_caster;
4905 // need replace effect 0 item by loot
4906 uint32 reagent_id = m_spellInfo->EffectItemType[0];
4908 if(!player->HasItemCount(reagent_id,1))
4909 return;
4911 // remove reagent
4912 uint32 count = 1;
4913 player->DestroyItemCount (reagent_id,count,true);
4915 // create some random items
4916 player->AutoStoreLoot(m_spellInfo->Id,LootTemplates_Spell);
4918 // learn random explicit discovery recipe (if any)
4919 if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
4920 player->learnSpell(discoveredSpell,false);
4921 return;
4924 break;
4926 case SPELLFAMILY_WARLOCK:
4928 switch(m_spellInfo->Id)
4930 // Healthstone creating spells
4931 case 6201:
4932 case 6202:
4933 case 5699:
4934 case 11729:
4935 case 11730:
4936 case 27230:
4937 case 47871:
4938 case 47878:
4940 uint32 itemtype;
4941 uint32 rank = 0;
4942 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4943 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4945 if((*i)->GetId() == 18692)
4947 rank = 1;
4948 break;
4950 else if((*i)->GetId() == 18693)
4952 rank = 2;
4953 break;
4957 static uint32 const itypes[8][3] = {
4958 { 5512,19004,19005}, // Minor Healthstone
4959 { 5511,19006,19007}, // Lesser Healthstone
4960 { 5509,19008,19009}, // Healthstone
4961 { 5510,19010,19011}, // Greater Healthstone
4962 { 9421,19012,19013}, // Major Healthstone
4963 {22103,22104,22105}, // Master Healthstone
4964 {36889,36890,36891}, // Demonic Healthstone
4965 {36892,36893,36894} // Fel Healthstone
4968 switch(m_spellInfo->Id)
4970 case 6201:
4971 itemtype=itypes[0][rank];break; // Minor Healthstone
4972 case 6202:
4973 itemtype=itypes[1][rank];break; // Lesser Healthstone
4974 case 5699:
4975 itemtype=itypes[2][rank];break; // Healthstone
4976 case 11729:
4977 itemtype=itypes[3][rank];break; // Greater Healthstone
4978 case 11730:
4979 itemtype=itypes[4][rank];break; // Major Healthstone
4980 case 27230:
4981 itemtype=itypes[5][rank];break; // Master Healthstone
4982 case 47871:
4983 itemtype=itypes[6][rank];break; // Demonic Healthstone
4984 case 47878:
4985 itemtype=itypes[7][rank];break; // Fel Healthstone
4986 default:
4987 return;
4989 DoCreateItem( effIndex, itemtype );
4990 return;
4992 // Everlasting Affliction
4993 case 47422:
4995 // Need refresh caster corruption auras on target
4996 Unit::AuraMap& suAuras = unitTarget->GetAuras();
4997 for(Unit::AuraMap::iterator itr = suAuras.begin(); itr != suAuras.end(); ++itr)
4999 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5000 if(spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK &&
5001 spellInfo->SpellFamilyFlags & 0x0000000000000002LL &&
5002 (*itr).second->GetCasterGUID()==m_caster->GetGUID())
5003 (*itr).second->RefreshAura();
5005 return;
5008 break;
5010 case SPELLFAMILY_PRIEST:
5012 switch(m_spellInfo->Id)
5014 // Pain and Suffering
5015 case 47948:
5017 if (!unitTarget)
5018 return;
5019 // Refresh Shadow Word: Pain on target
5020 Unit::AuraMap& auras = unitTarget->GetAuras();
5021 for(Unit::AuraMap::iterator itr = auras.begin(); itr != auras.end(); ++itr)
5023 SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
5024 if( spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST &&
5025 spellInfo->SpellFamilyFlags & 0x0000000000008000LL &&
5026 (*itr).second->GetCasterGUID() == m_caster->GetGUID())
5028 (*itr).second->RefreshAura();
5029 return;
5032 return;
5034 default:
5035 break;
5037 break;
5039 case SPELLFAMILY_HUNTER:
5041 switch(m_spellInfo->Id)
5043 // Chimera Shot
5044 case 53209:
5046 uint32 spellId = 0;
5047 int32 basePoint = 0;
5048 Unit::AuraMap& Auras = unitTarget->GetAuras();
5049 for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
5051 Aura *aura = (*i).second;
5052 if (aura->GetCasterGUID() != m_caster->GetGUID())
5053 continue;
5054 // Search only Serpent Sting, Viper Sting, Scorpid Sting auras
5055 uint64 familyFlag = aura->GetSpellProto()->SpellFamilyFlags;
5056 if (!(familyFlag & 0x000000800000C000LL))
5057 continue;
5058 // Refresh aura duration
5059 aura->RefreshAura();
5061 // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting.
5062 if (familyFlag & 0x0000000000004000LL && aura->GetEffIndex() == 0)
5064 spellId = 53353; // 53353 Chimera Shot - Serpent
5065 basePoint = aura->GetModifier()->m_amount * 5 * 40 / 100;
5067 // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting.
5068 if (familyFlag & 0x0000008000000000LL && aura->GetEffIndex() == 0)
5070 spellId = 53358; // 53358 Chimera Shot - Viper
5071 basePoint = aura->GetModifier()->m_amount * 4 * 60 / 100;
5073 // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute.
5074 if (familyFlag & 0x0000000000008000LL)
5075 spellId = 53359; // 53359 Chimera Shot - Scorpid
5076 // ?? nothing say in spell desc (possibly need addition check)
5077 //if (familyFlag & 0x0000010000000000LL || // dot
5078 // familyFlag & 0x0000100000000000LL) // stun
5080 // spellId = 53366; // 53366 Chimera Shot - Wyvern
5083 if (spellId)
5084 m_caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, false);
5085 return;
5087 default:
5088 break;
5090 break;
5092 case SPELLFAMILY_PALADIN:
5094 // Judgement
5095 if (m_spellInfo->SpellFamilyFlags & 0x0000000000800000LL)
5097 if(!unitTarget || !unitTarget->isAlive())
5098 return;
5099 uint32 spellId1 = 0;
5100 uint32 spellId2 = 0;
5102 // Judgement self add switch
5103 switch (m_spellInfo->Id)
5105 case 41467: break; // Judgement
5106 case 53407: spellId1 = 20184; break; // Judgement of Justice
5107 case 20271: // Judgement of Light
5108 case 57774: spellId1 = 20185; break; // Judgement of Light
5109 case 53408: spellId1 = 20186; break; // Judgement of Wisdom
5110 default:
5111 return;
5113 // all seals have aura dummy in 2 effect
5114 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
5115 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
5117 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
5118 // search seal (all seals have judgement's aura dummy spell id in 2 effect
5119 if ((*itr)->GetEffIndex() != 2 || !spellInfo || !IsSealSpell(spellInfo))
5120 continue;
5121 spellId2 = (*itr)->GetModifier()->m_amount;
5122 SpellEntry const *judge = sSpellStore.LookupEntry(spellId2);
5123 if (!judge)
5124 continue;
5125 break;
5127 if (spellId1)
5128 m_caster->CastSpell(unitTarget, spellId1, true);
5129 if (spellId2)
5130 m_caster->CastSpell(unitTarget, spellId2, true);
5131 return;
5134 case SPELLFAMILY_POTION:
5136 switch(m_spellInfo->Id)
5138 // Dreaming Glory
5139 case 28698:
5141 if(!unitTarget)
5142 return;
5143 unitTarget->CastSpell(unitTarget, 28694, true);
5144 break;
5146 // Netherbloom
5147 case 28702:
5149 if(!unitTarget)
5150 return;
5151 // 25% chance of casting a random buff
5152 if(roll_chance_i(75))
5153 return;
5155 // triggered spells are 28703 to 28707
5156 // Note: some sources say, that there was the possibility of
5157 // receiving a debuff. However, this seems to be removed by a patch.
5158 const uint32 spellid = 28703;
5160 // don't overwrite an existing aura
5161 for(uint8 i=0; i<5; i++)
5162 if(unitTarget->HasAura(spellid+i, 0))
5163 return;
5164 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
5165 break;
5168 // Nightmare Vine
5169 case 28720:
5171 if(!unitTarget)
5172 return;
5173 // 25% chance of casting Nightmare Pollen
5174 if(roll_chance_i(75))
5175 return;
5176 unitTarget->CastSpell(unitTarget, 28721, true);
5177 break;
5180 break;
5184 // normal DB scripted effect
5185 if(!unitTarget)
5186 return;
5188 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
5189 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
5192 void Spell::EffectSanctuary(uint32 /*i*/)
5194 if(!unitTarget)
5195 return;
5196 //unitTarget->CombatStop();
5198 unitTarget->CombatStop();
5199 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
5200 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
5201 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
5203 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
5207 void Spell::EffectAddComboPoints(uint32 /*i*/)
5209 if(!unitTarget)
5210 return;
5212 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5213 return;
5215 if(damage <= 0)
5216 return;
5218 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
5221 void Spell::EffectDuel(uint32 i)
5223 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
5224 return;
5226 Player *caster = (Player*)m_caster;
5227 Player *target = (Player*)unitTarget;
5229 // caster or target already have requested duel
5230 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
5231 return;
5233 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
5234 // Don't have to check the target's map since you cannot challenge someone across maps
5235 uint32 mapid = caster->GetMapId();
5236 if( mapid != 0 && mapid != 1 && mapid != 530 && mapid != 571 && mapid != 609)
5238 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5239 return;
5242 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
5243 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
5245 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5246 return;
5249 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
5250 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
5252 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
5253 return;
5256 //CREATE DUEL FLAG OBJECT
5257 GameObject* pGameObj = new GameObject;
5259 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
5261 Map *map = m_caster->GetMap();
5262 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id,
5263 map, m_caster->GetPhaseMask(),
5264 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
5265 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
5266 m_caster->GetPositionZ(),
5267 m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, 1))
5269 delete pGameObj;
5270 return;
5273 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
5274 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
5275 int32 duration = GetSpellDuration(m_spellInfo);
5276 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5277 pGameObj->SetSpellId(m_spellInfo->Id);
5279 m_caster->AddGameObject(pGameObj);
5280 map->Add(pGameObj);
5281 //END
5283 // Send request
5284 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
5285 data << pGameObj->GetGUID();
5286 data << caster->GetGUID();
5287 caster->GetSession()->SendPacket(&data);
5288 target->GetSession()->SendPacket(&data);
5290 // create duel-info
5291 DuelInfo *duel = new DuelInfo;
5292 duel->initiator = caster;
5293 duel->opponent = target;
5294 duel->startTime = 0;
5295 duel->startTimer = 0;
5296 caster->duel = duel;
5298 DuelInfo *duel2 = new DuelInfo;
5299 duel2->initiator = caster;
5300 duel2->opponent = caster;
5301 duel2->startTime = 0;
5302 duel2->startTimer = 0;
5303 target->duel = duel2;
5305 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5306 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5309 void Spell::EffectStuck(uint32 /*i*/)
5311 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5312 return;
5314 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5315 return;
5317 Player* pTarget = (Player*)unitTarget;
5319 sLog.outDebug("Spell Effect: Stuck");
5320 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());
5322 if(pTarget->isInFlight())
5323 return;
5325 // homebind location is loaded always
5326 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5328 // Stuck spell trigger Hearthstone cooldown
5329 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5330 if(!spellInfo)
5331 return;
5332 Spell spell(pTarget,spellInfo,true,0);
5333 spell.SendSpellCooldown();
5336 void Spell::EffectSummonPlayer(uint32 /*i*/)
5338 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5339 return;
5341 // Evil Twin (ignore player summon, but hide this for summoner)
5342 if(unitTarget->GetDummyAura(23445))
5343 return;
5345 float x,y,z;
5346 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5348 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5350 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5351 data << uint64(m_caster->GetGUID()); // summoner guid
5352 data << uint32(m_caster->GetZoneId()); // summoner zone
5353 data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILISECONDS); // auto decline after msecs
5354 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5357 static ScriptInfo generateActivateCommand()
5359 ScriptInfo si;
5360 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5361 return si;
5364 void Spell::EffectActivateObject(uint32 effect_idx)
5366 if(!gameObjTarget)
5367 return;
5369 static ScriptInfo activateCommand = generateActivateCommand();
5371 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5373 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5376 void Spell::EffectApplyGlyph(uint32 i)
5378 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5379 return;
5381 Player *player = (Player*)m_caster;
5383 // apply new one
5384 if(uint32 glyph = m_spellInfo->EffectMiscValue[i])
5386 if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
5388 if(GlyphSlotEntry const *gs = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_glyphIndex)))
5390 if(gp->TypeFlags != gs->TypeFlags)
5392 SendCastResult(SPELL_FAILED_INVALID_GLYPH);
5393 return; // glyph slot mismatch
5397 // remove old glyph
5398 if(uint32 oldglyph = player->GetGlyph(m_glyphIndex))
5400 if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
5402 player->RemoveAurasDueToSpell(old_gp->SpellId);
5403 player->SetGlyph(m_glyphIndex, 0);
5407 player->CastSpell(m_caster, gp->SpellId, true);
5408 player->SetGlyph(m_glyphIndex, glyph);
5413 void Spell::EffectSummonTotem(uint32 i)
5415 uint8 slot = 0;
5416 switch(m_spellInfo->EffectMiscValueB[i])
5418 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5419 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5420 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5421 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5422 // Battle standard case
5423 case SUMMON_TYPE_TOTEM: slot = 254; break;
5424 // jewelery statue case, like totem without slot
5425 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5426 default: return;
5429 if(slot < MAX_TOTEM)
5431 uint64 guid = m_caster->m_TotemSlot[slot];
5432 if(guid != 0)
5434 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5435 if(OldTotem && OldTotem->isTotem())
5436 ((Totem*)OldTotem)->UnSummon();
5440 uint32 team = 0;
5441 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5442 team = ((Player*)m_caster)->GetTeam();
5444 Totem* pTotem = new Totem;
5446 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_caster->GetPhaseMask(),
5447 m_spellInfo->EffectMiscValue[i], team ))
5449 delete pTotem;
5450 return;
5453 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5455 float x,y,z;
5456 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5458 // totem must be at same Z in case swimming caster and etc.
5459 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5460 z = m_caster->GetPositionZ();
5462 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5464 if(slot < MAX_TOTEM)
5465 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5467 pTotem->SetOwner(m_caster->GetGUID());
5468 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5470 int32 duration=GetSpellDuration(m_spellInfo);
5471 if(Player* modOwner = m_caster->GetSpellModOwner())
5472 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5473 pTotem->SetDuration(duration);
5475 if (damage) // if not spell info, DB values used
5477 pTotem->SetMaxHealth(damage);
5478 pTotem->SetHealth(damage);
5481 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5483 if(m_caster->GetTypeId() == TYPEID_PLAYER)
5484 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5486 pTotem->Summon(m_caster);
5488 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5490 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5491 data << uint8(slot);
5492 data << uint64(pTotem->GetGUID());
5493 data << uint32(duration);
5494 data << uint32(m_spellInfo->Id);
5495 ((Player*)m_caster)->SendDirectMessage(&data);
5499 void Spell::EffectEnchantHeldItem(uint32 i)
5501 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5502 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5503 return;
5505 Player* item_owner = (Player*)unitTarget;
5506 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5508 if(!item )
5509 return;
5511 // must be equipped
5512 if(!item ->IsEquipped())
5513 return;
5515 if (m_spellInfo->EffectMiscValue[i])
5517 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5518 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5519 if(!duration)
5520 duration = m_currentBasePoints[i]+1; //Base points after ..
5521 if(!duration)
5522 duration = 10; //10 seconds for enchants which don't have listed duration
5524 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5525 if(!pEnchant)
5526 return;
5528 // Always go to temp enchantment slot
5529 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5531 // Enchantment will not be applied if a different one already exists
5532 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5533 return;
5535 // Apply the temporary enchantment
5536 item->SetEnchantment(slot, enchant_id, duration*IN_MILISECONDS, 0);
5537 item_owner->ApplyEnchantment(item,slot,true);
5541 void Spell::EffectDisEnchant(uint32 /*i*/)
5543 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5544 return;
5546 Player* p_caster = (Player*)m_caster;
5547 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5548 return;
5550 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5552 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5554 // item will be removed at disenchanting end
5557 void Spell::EffectInebriate(uint32 /*i*/)
5559 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5560 return;
5562 Player *player = (Player*)unitTarget;
5563 uint16 currentDrunk = player->GetDrunkValue();
5564 uint16 drunkMod = damage * 256;
5565 if (currentDrunk + drunkMod > 0xFFFF)
5566 currentDrunk = 0xFFFF;
5567 else
5568 currentDrunk += drunkMod;
5569 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5572 void Spell::EffectFeedPet(uint32 i)
5574 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5575 return;
5577 Player *_player = (Player*)m_caster;
5579 Item* foodItem = m_targets.getItemTarget();
5580 if(!foodItem)
5581 return;
5583 Pet *pet = _player->GetPet();
5584 if(!pet)
5585 return;
5587 if(!pet->isAlive())
5588 return;
5590 int32 benefit = pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel);
5591 if(benefit <= 0)
5592 return;
5594 uint32 count = 1;
5595 _player->DestroyItemCount(foodItem,count,true);
5596 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5598 m_caster->CastCustomSpell(pet,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5601 void Spell::EffectDismissPet(uint32 /*i*/)
5603 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5604 return;
5606 Pet* pet = m_caster->GetPet();
5608 // not let dismiss dead pet
5609 if(!pet||!pet->isAlive())
5610 return;
5612 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5615 void Spell::EffectSummonObject(uint32 i)
5617 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5619 uint8 slot = 0;
5620 switch(m_spellInfo->Effect[i])
5622 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5623 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5624 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5625 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5626 default: return;
5629 uint64 guid = m_caster->m_ObjectSlot[slot];
5630 if(guid != 0)
5632 GameObject* obj = NULL;
5633 if( m_caster )
5634 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5636 if(obj) obj->Delete();
5637 m_caster->m_ObjectSlot[slot] = 0;
5640 GameObject* pGameObj = new GameObject;
5642 float x,y,z;
5643 // If dest location if present
5644 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5646 x = m_targets.m_destX;
5647 y = m_targets.m_destY;
5648 z = m_targets.m_destZ;
5650 // Summon in random point all other units if location present
5651 else
5652 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5654 Map *map = m_caster->GetMap();
5655 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map,
5656 m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, 1))
5658 delete pGameObj;
5659 return;
5662 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5663 int32 duration = GetSpellDuration(m_spellInfo);
5664 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
5665 pGameObj->SetSpellId(m_spellInfo->Id);
5666 m_caster->AddGameObject(pGameObj);
5668 map->Add(pGameObj);
5669 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5670 data << pGameObj->GetGUID();
5671 m_caster->SendMessageToSet(&data,true);
5673 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5676 void Spell::EffectResurrect(uint32 /*effIndex*/)
5678 if(!unitTarget)
5679 return;
5680 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5681 return;
5683 if(unitTarget->isAlive())
5684 return;
5685 if(!unitTarget->IsInWorld())
5686 return;
5688 switch (m_spellInfo->Id)
5690 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5691 case 8342:
5692 if (roll_chance_i(67))
5694 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5695 return;
5697 break;
5698 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5699 case 22999:
5700 if (roll_chance_i(50))
5702 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5703 return;
5705 break;
5706 default:
5707 break;
5710 Player* pTarget = ((Player*)unitTarget);
5712 if(pTarget->isRessurectRequested()) // already have one active request
5713 return;
5715 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5716 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5718 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5719 SendResurrectRequest(pTarget);
5722 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5724 if(!unitTarget || !unitTarget->isAlive())
5725 return;
5727 if( unitTarget->m_extraAttacks )
5728 return;
5730 unitTarget->m_extraAttacks = damage;
5733 void Spell::EffectParry(uint32 /*i*/)
5735 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5736 ((Player*)unitTarget)->SetCanParry(true);
5739 void Spell::EffectBlock(uint32 /*i*/)
5741 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
5742 ((Player*)unitTarget)->SetCanBlock(true);
5745 void Spell::EffectMomentMove(uint32 i)
5747 if(unitTarget->isInFlight())
5748 return;
5750 if( m_spellInfo->rangeIndex== 1) //self range
5752 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5754 // before caster
5755 float fx,fy,fz;
5756 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5757 float ox,oy,oz;
5758 unitTarget->GetPosition(ox,oy,oz);
5760 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5761 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(unitTarget->GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5763 fx = fx2;
5764 fy = fy2;
5765 fz = fz2;
5766 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5769 unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(),unitTarget==m_caster);
5773 void Spell::EffectReputation(uint32 i)
5775 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5776 return;
5778 Player *_player = (Player*)unitTarget;
5780 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5782 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5784 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5786 if(!factionEntry)
5787 return;
5789 _player->GetReputationMgr().ModifyReputation(factionEntry,rep_change);
5792 void Spell::EffectQuestComplete(uint32 i)
5794 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5795 return;
5797 Player *_player = (Player*)m_caster;
5799 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5800 _player->AreaExploredOrEventHappens(quest_id);
5803 void Spell::EffectSelfResurrect(uint32 i)
5805 if(!unitTarget || unitTarget->isAlive())
5806 return;
5807 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5808 return;
5809 if(!unitTarget->IsInWorld())
5810 return;
5812 uint32 health = 0;
5813 uint32 mana = 0;
5815 // flat case
5816 if(damage < 0)
5818 health = uint32(-damage);
5819 mana = m_spellInfo->EffectMiscValue[i];
5821 // percent case
5822 else
5824 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5825 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5826 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5829 Player *plr = ((Player*)unitTarget);
5830 plr->ResurrectPlayer(0.0f);
5832 plr->SetHealth( health );
5833 plr->SetPower(POWER_MANA, mana );
5834 plr->SetPower(POWER_RAGE, 0 );
5835 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5837 plr->SpawnCorpseBones();
5839 plr->SaveToDB();
5842 void Spell::EffectSkinning(uint32 /*i*/)
5844 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5845 return;
5846 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5847 return;
5849 Creature* creature = (Creature*) unitTarget;
5850 int32 targetLevel = creature->getLevel();
5852 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5854 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5855 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5857 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5859 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5861 // Double chances for elites
5862 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5865 void Spell::EffectCharge(uint32 /*i*/)
5867 if(!unitTarget || !m_caster)
5868 return;
5870 float x, y, z;
5871 unitTarget->GetContactPoint(m_caster, x, y, z);
5872 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5873 ((Creature *)unitTarget)->StopMoving();
5875 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5876 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5878 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5879 m_caster->GetMap()->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5881 // not all charge effects used in negative spells
5882 if ( !IsPositiveSpell(m_spellInfo->Id))
5883 m_caster->Attack(unitTarget,true);
5886 void Spell::EffectSummonCritter(uint32 i)
5888 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5889 return;
5890 Player* player = (Player*)m_caster;
5892 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5893 if(!pet_entry)
5894 return;
5896 Pet* old_critter = player->GetMiniPet();
5898 // for same pet just despawn
5899 if(old_critter && old_critter->GetEntry() == pet_entry)
5901 player->RemoveMiniPet();
5902 return;
5905 // despawn old pet before summon new
5906 if(old_critter)
5907 player->RemoveMiniPet();
5909 // summon new pet
5910 Pet* critter = new Pet(MINI_PET);
5912 Map *map = m_caster->GetMap();
5913 uint32 pet_number = objmgr.GeneratePetNumber();
5914 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, m_caster->GetPhaseMask(),
5915 pet_entry, pet_number))
5917 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5918 delete critter;
5919 return;
5922 float x,y,z;
5923 // If dest location if present
5924 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5926 x = m_targets.m_destX;
5927 y = m_targets.m_destY;
5928 z = m_targets.m_destZ;
5930 // Summon if dest location not present near caster
5931 else
5932 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5934 critter->Relocate(x,y,z,m_caster->GetOrientation());
5936 if(!critter->IsPositionValid())
5938 sLog.outError("Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",
5939 critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5940 delete critter;
5941 return;
5944 critter->SetOwnerGUID(m_caster->GetGUID());
5945 critter->SetCreatorGUID(m_caster->GetGUID());
5946 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5947 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5949 critter->AIM_Initialize();
5950 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5951 critter->SetMaxHealth(1);
5952 critter->SetHealth(1);
5953 critter->SetLevel(1);
5955 // set timer for unsummon
5956 int32 duration = GetSpellDuration(m_spellInfo);
5957 if(duration > 0)
5958 critter->SetDuration(duration);
5960 std::string name = player->GetName();
5961 name.append(petTypeSuffix[critter->getPetType()]);
5962 critter->SetName( name );
5963 player->SetMiniPet(critter);
5965 map->Add((Creature*)critter);
5968 void Spell::EffectKnockBack(uint32 i)
5970 if(!unitTarget || !m_caster)
5971 return;
5973 // Effect only works on players
5974 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5975 return;
5977 float vsin = sin(m_caster->GetAngle(unitTarget));
5978 float vcos = cos(m_caster->GetAngle(unitTarget));
5980 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5981 data.append(unitTarget->GetPackGUID());
5982 data << uint32(0); // Sequence
5983 data << float(vcos); // x direction
5984 data << float(vsin); // y direction
5985 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5986 data << float(damage/-10); // Z Movement speed (vertical)
5988 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5991 void Spell::EffectSendTaxi(uint32 i)
5993 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5994 return;
5996 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5997 if(!entry)
5998 return;
6000 std::vector<uint32> nodes;
6002 nodes.resize(2);
6003 nodes[0] = entry->from;
6004 nodes[1] = entry->to;
6006 uint32 mountid = 0;
6007 switch(m_spellInfo->Id)
6009 case 31606: //Stormcrow Amulet
6010 mountid = 17447;
6011 break;
6012 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
6013 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
6014 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
6015 mountid = 22840;
6016 break;
6017 case 34905: //Stealth Flight
6018 mountid = 6851;
6019 break;
6020 case 45883: //Amber Ledge to Beryl Point
6021 mountid = 23524;
6022 break;
6023 case 46064: //Amber Ledge to Coldarra
6024 mountid = 6371;
6025 break;
6026 case 53335: //Stormwind Harbor Flight - Peaceful
6027 mountid = 6852;
6028 break;
6031 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
6035 void Spell::EffectPlayerPull(uint32 i)
6037 if(!unitTarget || !m_caster)
6038 return;
6040 // Effect only works on players
6041 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
6042 return;
6044 float vsin = sin(unitTarget->GetAngle(m_caster));
6045 float vcos = cos(unitTarget->GetAngle(m_caster));
6047 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
6048 data.append(unitTarget->GetPackGUID());
6049 data << uint32(0); // Sequence
6050 data << float(vcos); // x direction
6051 data << float(vsin); // y direction
6052 // Horizontal speed
6053 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
6054 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
6056 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
6059 void Spell::EffectDispelMechanic(uint32 i)
6061 if(!unitTarget)
6062 return;
6064 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
6066 Unit::AuraMap& Auras = unitTarget->GetAuras();
6067 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
6069 next = iter;
6070 ++next;
6071 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
6072 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
6074 unitTarget->RemoveAurasDueToSpell(spell->Id);
6075 if(Auras.empty())
6076 break;
6077 else
6078 next = Auras.begin();
6081 return;
6084 void Spell::EffectSummonDeadPet(uint32 /*i*/)
6086 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6087 return;
6088 Player *_player = (Player*)m_caster;
6089 Pet *pet = _player->GetPet();
6090 if(!pet)
6091 return;
6092 if(pet->isAlive())
6093 return;
6094 if(damage < 0)
6095 return;
6096 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
6097 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
6098 pet->setDeathState( ALIVE );
6099 pet->clearUnitState(UNIT_STAT_ALL_STATE);
6100 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
6102 pet->AIM_Initialize();
6104 _player->PetSpellInitialize();
6105 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
6108 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
6110 float mana = 0;
6111 for(int slot = 0; slot < MAX_TOTEM; ++slot)
6113 if(!m_caster->m_TotemSlot[slot])
6114 continue;
6116 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
6117 if(totem && totem->isTotem())
6119 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
6120 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
6121 if(spellInfo)
6122 mana += spellInfo->manaCost * damage / 100;
6123 ((Totem*)totem)->UnSummon();
6127 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
6128 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
6131 void Spell::EffectDurabilityDamage(uint32 i)
6133 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6134 return;
6136 int32 slot = m_spellInfo->EffectMiscValue[i];
6138 // FIXME: some spells effects have value -1/-2
6139 // Possibly its mean -1 all player equipped items and -2 all items
6140 if(slot < 0)
6142 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
6143 return;
6146 // invalid slot value
6147 if(slot >= INVENTORY_SLOT_BAG_END)
6148 return;
6150 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6151 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
6154 void Spell::EffectDurabilityDamagePCT(uint32 i)
6156 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6157 return;
6159 int32 slot = m_spellInfo->EffectMiscValue[i];
6161 // FIXME: some spells effects have value -1/-2
6162 // Possibly its mean -1 all player equipped items and -2 all items
6163 if(slot < 0)
6165 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
6166 return;
6169 // invalid slot value
6170 if(slot >= INVENTORY_SLOT_BAG_END)
6171 return;
6173 if(damage <= 0)
6174 return;
6176 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
6177 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
6180 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
6182 if(!unitTarget)
6183 return;
6185 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
6188 void Spell::EffectTransmitted(uint32 effIndex)
6190 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
6192 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
6194 if (!goinfo)
6196 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
6197 return;
6200 float fx,fy,fz;
6202 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6204 fx = m_targets.m_destX;
6205 fy = m_targets.m_destY;
6206 fz = m_targets.m_destZ;
6208 //FIXME: this can be better check for most objects but still hack
6209 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
6211 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
6212 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6214 else
6216 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6217 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
6218 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
6220 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
6223 Map *cMap = m_caster->GetMap();
6225 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
6227 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
6228 { // but this is not proper, we really need to ignore not materialized objects
6229 SendCastResult(SPELL_FAILED_NOT_HERE);
6230 SendChannelUpdate(0);
6231 return;
6234 // replace by water level in this case
6235 fz = cMap->GetWaterLevel(fx,fy);
6237 // if gameobject is summoning object, it should be spawned right on caster's position
6238 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
6240 m_caster->GetPosition(fx,fy,fz);
6243 GameObject* pGameObj = new GameObject;
6245 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
6246 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, 1))
6248 delete pGameObj;
6249 return;
6252 int32 duration = GetSpellDuration(m_spellInfo);
6254 switch(goinfo->type)
6256 case GAMEOBJECT_TYPE_FISHINGNODE:
6258 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
6259 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6261 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
6262 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
6263 int32 lastSec;
6264 switch(urand(0, 3))
6266 case 0: lastSec = 3; break;
6267 case 1: lastSec = 7; break;
6268 case 2: lastSec = 13; break;
6269 case 3: lastSec = 17; break;
6272 duration = duration - lastSec*IN_MILISECONDS + FISHING_BOBBER_READY_TIME*IN_MILISECONDS;
6273 break;
6275 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
6277 if(m_caster->GetTypeId()==TYPEID_PLAYER)
6279 pGameObj->AddUniqueUse((Player*)m_caster);
6280 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
6282 break;
6284 case GAMEOBJECT_TYPE_FISHINGHOLE:
6285 case GAMEOBJECT_TYPE_CHEST:
6286 default:
6288 break;
6292 pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6294 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
6296 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6297 pGameObj->SetSpellId(m_spellInfo->Id);
6299 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted");
6300 //m_caster->AddGameObject(pGameObj);
6301 //m_ObjToDel.push_back(pGameObj);
6303 cMap->Add(pGameObj);
6305 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
6306 data << uint64(pGameObj->GetGUID());
6307 m_caster->SendMessageToSet(&data,true);
6309 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
6311 GameObject* linkedGO = new GameObject;
6312 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
6313 m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, 1))
6315 linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
6316 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
6317 linkedGO->SetSpellId(m_spellInfo->Id);
6318 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
6320 linkedGO->GetMap()->Add(linkedGO);
6322 else
6324 delete linkedGO;
6325 linkedGO = NULL;
6326 return;
6331 void Spell::EffectProspecting(uint32 /*i*/)
6333 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6334 return;
6336 Player* p_caster = (Player*)m_caster;
6337 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6338 return;
6340 if(itemTarget->GetCount() < 5)
6341 return;
6343 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6345 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6346 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6347 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6350 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6353 void Spell::EffectMilling(uint32 /*i*/)
6355 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6356 return;
6358 Player* p_caster = (Player*)m_caster;
6359 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_HERBS))
6360 return;
6362 if(itemTarget->GetCount() < 5)
6363 return;
6365 if( sWorld.getConfig(CONFIG_SKILL_MILLING))
6367 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_INSCRIPTION);
6368 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6369 p_caster->UpdateGatherSkill(SKILL_INSCRIPTION, SkillValue, reqSkillValue);
6372 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_MILLING);
6375 void Spell::EffectSkill(uint32 /*i*/)
6377 sLog.outDebug("WORLD: SkillEFFECT");
6380 void Spell::EffectSummonDemon(uint32 i)
6382 // select center of summon position
6383 float center_x = m_targets.m_destX;
6384 float center_y = m_targets.m_destY;
6385 float center_z = m_targets.m_destZ;
6387 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
6389 int32 amount = damage > 0 ? damage : 1;
6391 for(int32 count = 0; count < amount; ++count)
6393 float px, py, pz;
6394 // If dest location if present
6395 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
6397 // Summon 1 unit in dest location
6398 if (count == 0)
6400 px = m_targets.m_destX;
6401 py = m_targets.m_destY;
6402 pz = m_targets.m_destZ;
6404 // Summon in random point all other units if location present
6405 else
6406 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
6408 // Summon if dest location not present near caster
6409 else
6410 m_caster->GetClosePoint(px,py,pz,3.0f);
6412 int32 duration = GetSpellDuration(m_spellInfo);
6414 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,duration);
6415 if (!Charmed) // something fatal, not attempt more
6416 return;
6418 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6419 Charmed->SetLevel(m_caster->getLevel());
6421 // TODO: Add damage/mana/hp according to level
6423 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6425 // Enslave demon effect, without mana cost and cooldown
6426 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6428 // Inferno effect
6429 Charmed->CastSpell(Charmed, 22703, true, 0);
6434 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6435 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6436 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6437 This is why we use a half sec delay between the visual effect and the resurrection itself */
6438 void Spell::EffectSpiritHeal(uint32 /*i*/)
6441 if(!unitTarget || unitTarget->isAlive())
6442 return;
6443 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6444 return;
6445 if(!unitTarget->IsInWorld())
6446 return;
6448 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6449 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6450 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6451 ((Player*)unitTarget)->SpawnCorpseBones();
6455 // remove insignia spell effect
6456 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6458 sLog.outDebug("Effect: SkinPlayerCorpse");
6459 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6460 return;
6462 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6465 void Spell::EffectStealBeneficialBuff(uint32 i)
6467 sLog.outDebug("Effect: StealBeneficialBuff");
6469 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6470 return;
6472 std::vector <Aura *> steal_list;
6473 // Create dispel mask by dispel type
6474 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6475 Unit::AuraMap const& auras = unitTarget->GetAuras();
6476 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6478 Aura *aur = (*itr).second;
6479 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6481 // Need check for passive? this
6482 if (aur->IsPositive() && !aur->IsPassive() && !(aur->GetSpellProto()->AttributesEx4 & SPELL_ATTR_EX4_NOT_STEALABLE))
6483 steal_list.push_back(aur);
6486 // Ok if exist some buffs for dispel try dispel it
6487 if (!steal_list.empty())
6489 std::list < std::pair<uint32,uint64> > success_list;
6490 int32 list_size = steal_list.size();
6491 // Dispell N = damage buffs (or while exist buffs for dispel)
6492 for (int32 count=0; count < damage && list_size > 0; ++count)
6494 // Random select buff for dispel
6495 Aura *aur = steal_list[urand(0, list_size-1)];
6496 // Not use chance for steal
6497 // TODO possible need do it
6498 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6500 // Remove buff from list for prevent doubles
6501 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6503 Aura *stealed = *j;
6504 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6506 j = steal_list.erase(j);
6507 --list_size;
6509 else
6510 ++j;
6513 // Really try steal and send log
6514 if (!success_list.empty())
6516 int32 count = success_list.size();
6517 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6518 data.append(unitTarget->GetPackGUID()); // Victim GUID
6519 data.append(m_caster->GetPackGUID()); // Caster GUID
6520 data << uint32(m_spellInfo->Id); // Dispell spell id
6521 data << uint8(0); // not used
6522 data << uint32(count); // count
6523 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6525 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6526 data << uint32(spellInfo->Id); // Spell Id
6527 data << uint8(0); // 0 - steals !=0 transfers
6528 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6530 m_caster->SendMessageToSet(&data, true);
6535 void Spell::EffectKillCredit(uint32 i)
6537 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6538 return;
6540 ((Player*)unitTarget)->RewardPlayerAndGroupAtEvent(m_spellInfo->EffectMiscValue[i], unitTarget);
6543 void Spell::EffectQuestFail(uint32 i)
6545 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6546 return;
6548 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);
6551 void Spell::EffectActivateRune(uint32 eff_idx)
6553 if(m_caster->GetTypeId() != TYPEID_PLAYER)
6554 return;
6556 Player *plr = (Player*)m_caster;
6558 if(plr->getClass() != CLASS_DEATH_KNIGHT)
6559 return;
6561 for(uint32 j = 0; j < MAX_RUNES; ++j)
6563 if(plr->GetRuneCooldown(j) && plr->GetCurrentRune(j) == m_spellInfo->EffectMiscValue[eff_idx])
6565 plr->SetRuneCooldown(j, 0);
6570 void Spell::EffectTitanGrip(uint32 /*eff_idx*/)
6572 if (unitTarget && unitTarget->GetTypeId() == TYPEID_PLAYER)
6573 ((Player*)unitTarget)->SetCanTitanGrip(true);
6576 void Spell::EffectRenamePet(uint32 /*eff_idx*/)
6578 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT ||
6579 !((Creature*)unitTarget)->isPet() || ((Pet*)unitTarget)->getPetType() != HUNTER_PET)
6580 return;
6582 unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);