[2008_10_31_01_mangos_creature_template.sql] Creature related code and DB cleanups.
[getmangos.git] / src / game / SpellEffects.cpp
blob5077d87e73bce2ae3c60f920f5ce74a0d2e99711
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "SharedDefines.h"
21 #include "Database/DatabaseEnv.h"
22 #include "WorldPacket.h"
23 #include "WorldSession.h"
24 #include "Opcodes.h"
25 #include "Log.h"
26 #include "UpdateMask.h"
27 #include "World.h"
28 #include "ObjectMgr.h"
29 #include "SpellMgr.h"
30 #include "Player.h"
31 #include "SkillExtraItems.h"
32 #include "Unit.h"
33 #include "CreatureAI.h"
34 #include "Spell.h"
35 #include "DynamicObject.h"
36 #include "SpellAuras.h"
37 #include "Group.h"
38 #include "UpdateData.h"
39 #include "MapManager.h"
40 #include "ObjectAccessor.h"
41 #include "SharedDefines.h"
42 #include "Pet.h"
43 #include "GameObject.h"
44 #include "GossipDef.h"
45 #include "Creature.h"
46 #include "Totem.h"
47 #include "CreatureAI.h"
48 #include "BattleGround.h"
49 #include "BattleGroundEY.h"
50 #include "BattleGroundWS.h"
51 #include "VMapFactory.h"
52 #include "Language.h"
53 #include "SocialMgr.h"
54 #include "Util.h"
55 #include "TemporarySummon.h"
57 pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
59 &Spell::EffectNULL, // 0
60 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL
61 &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE
62 &Spell::EffectDummy, // 3 SPELL_EFFECT_DUMMY
63 &Spell::EffectUnused, // 4 SPELL_EFFECT_PORTAL_TELEPORT unused
64 &Spell::EffectTeleportUnits, // 5 SPELL_EFFECT_TELEPORT_UNITS
65 &Spell::EffectApplyAura, // 6 SPELL_EFFECT_APPLY_AURA
66 &Spell::EffectEnvirinmentalDMG, // 7 SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
67 &Spell::EffectPowerDrain, // 8 SPELL_EFFECT_POWER_DRAIN
68 &Spell::EffectHealthLeech, // 9 SPELL_EFFECT_HEALTH_LEECH
69 &Spell::EffectHeal, // 10 SPELL_EFFECT_HEAL
70 &Spell::EffectUnused, // 11 SPELL_EFFECT_BIND
71 &Spell::EffectNULL, // 12 SPELL_EFFECT_PORTAL
72 &Spell::EffectUnused, // 13 SPELL_EFFECT_RITUAL_BASE unused
73 &Spell::EffectUnused, // 14 SPELL_EFFECT_RITUAL_SPECIALIZE unused
74 &Spell::EffectUnused, // 15 SPELL_EFFECT_RITUAL_ACTIVATE_PORTAL unused
75 &Spell::EffectQuestComplete, // 16 SPELL_EFFECT_QUEST_COMPLETE
76 &Spell::EffectWeaponDmg, // 17 SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
77 &Spell::EffectResurrect, // 18 SPELL_EFFECT_RESURRECT
78 &Spell::EffectAddExtraAttacks, // 19 SPELL_EFFECT_ADD_EXTRA_ATTACKS
79 &Spell::EffectUnused, // 20 SPELL_EFFECT_DODGE one spell: Dodge
80 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND)
81 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY
82 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block
83 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM
84 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON
85 &Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
86 &Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
87 &Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
88 &Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
89 &Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
90 &Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
91 &Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
92 &Spell::EffectOpenLock, // 33 SPELL_EFFECT_OPEN_LOCK
93 &Spell::EffectSummonChangeItem, // 34 SPELL_EFFECT_SUMMON_CHANGE_ITEM
94 &Spell::EffectApplyAreaAura, // 35 SPELL_EFFECT_APPLY_AREA_AURA_PARTY
95 &Spell::EffectLearnSpell, // 36 SPELL_EFFECT_LEARN_SPELL
96 &Spell::EffectUnused, // 37 SPELL_EFFECT_SPELL_DEFENSE one spell: SPELLDEFENSE (DND)
97 &Spell::EffectDispel, // 38 SPELL_EFFECT_DISPEL
98 &Spell::EffectUnused, // 39 SPELL_EFFECT_LANGUAGE
99 &Spell::EffectDualWield, // 40 SPELL_EFFECT_DUAL_WIELD
100 &Spell::EffectSummonWild, // 41 SPELL_EFFECT_SUMMON_WILD
101 &Spell::EffectSummonGuardian, // 42 SPELL_EFFECT_SUMMON_GUARDIAN
102 &Spell::EffectTeleUnitsFaceCaster, // 43 SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
103 &Spell::EffectLearnSkill, // 44 SPELL_EFFECT_SKILL_STEP
104 &Spell::EffectAddHonor, // 45 SPELL_EFFECT_ADD_HONOR honor/pvp related
105 &Spell::EffectNULL, // 46 SPELL_EFFECT_SPAWN we must spawn pet there
106 &Spell::EffectTradeSkill, // 47 SPELL_EFFECT_TRADE_SKILL
107 &Spell::EffectUnused, // 48 SPELL_EFFECT_STEALTH one spell: Base Stealth
108 &Spell::EffectUnused, // 49 SPELL_EFFECT_DETECT one spell: Detect
109 &Spell::EffectTransmitted, // 50 SPELL_EFFECT_TRANS_DOOR
110 &Spell::EffectUnused, // 51 SPELL_EFFECT_FORCE_CRITICAL_HIT unused
111 &Spell::EffectUnused, // 52 SPELL_EFFECT_GUARANTEE_HIT one spell: zzOLDCritical Shot
112 &Spell::EffectEnchantItemPerm, // 53 SPELL_EFFECT_ENCHANT_ITEM
113 &Spell::EffectEnchantItemTmp, // 54 SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
114 &Spell::EffectTameCreature, // 55 SPELL_EFFECT_TAMECREATURE
115 &Spell::EffectSummonPet, // 56 SPELL_EFFECT_SUMMON_PET
116 &Spell::EffectLearnPetSpell, // 57 SPELL_EFFECT_LEARN_PET_SPELL
117 &Spell::EffectWeaponDmg, // 58 SPELL_EFFECT_WEAPON_DAMAGE
118 &Spell::EffectOpenSecretSafe, // 59 SPELL_EFFECT_OPEN_LOCK_ITEM
119 &Spell::EffectProficiency, // 60 SPELL_EFFECT_PROFICIENCY
120 &Spell::EffectSendEvent, // 61 SPELL_EFFECT_SEND_EVENT
121 &Spell::EffectPowerBurn, // 62 SPELL_EFFECT_POWER_BURN
122 &Spell::EffectThreat, // 63 SPELL_EFFECT_THREAT
123 &Spell::EffectTriggerSpell, // 64 SPELL_EFFECT_TRIGGER_SPELL
124 &Spell::EffectUnused, // 65 SPELL_EFFECT_HEALTH_FUNNEL unused
125 &Spell::EffectUnused, // 66 SPELL_EFFECT_POWER_FUNNEL unused
126 &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH
127 &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST
128 &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT
129 &Spell::EffectPull, // 70 SPELL_EFFECT_PULL one spell: Distract Move
130 &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET
131 &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT
132 &Spell::EffectSummonGuardian, // 73 SPELL_EFFECT_SUMMON_POSSESSED
133 &Spell::EffectSummonTotem, // 74 SPELL_EFFECT_SUMMON_TOTEM
134 &Spell::EffectHealMechanical, // 75 SPELL_EFFECT_HEAL_MECHANICAL one spell: Mechanical Patch Kit
135 &Spell::EffectSummonObjectWild, // 76 SPELL_EFFECT_SUMMON_OBJECT_WILD
136 &Spell::EffectScriptEffect, // 77 SPELL_EFFECT_SCRIPT_EFFECT
137 &Spell::EffectUnused, // 78 SPELL_EFFECT_ATTACK
138 &Spell::EffectSanctuary, // 79 SPELL_EFFECT_SANCTUARY
139 &Spell::EffectAddComboPoints, // 80 SPELL_EFFECT_ADD_COMBO_POINTS
140 &Spell::EffectUnused, // 81 SPELL_EFFECT_CREATE_HOUSE one spell: Create House (TEST)
141 &Spell::EffectNULL, // 82 SPELL_EFFECT_BIND_SIGHT
142 &Spell::EffectDuel, // 83 SPELL_EFFECT_DUEL
143 &Spell::EffectStuck, // 84 SPELL_EFFECT_STUCK
144 &Spell::EffectSummonPlayer, // 85 SPELL_EFFECT_SUMMON_PLAYER
145 &Spell::EffectActivateObject, // 86 SPELL_EFFECT_ACTIVATE_OBJECT
146 &Spell::EffectSummonTotem, // 87 SPELL_EFFECT_SUMMON_TOTEM_SLOT1
147 &Spell::EffectSummonTotem, // 88 SPELL_EFFECT_SUMMON_TOTEM_SLOT2
148 &Spell::EffectSummonTotem, // 89 SPELL_EFFECT_SUMMON_TOTEM_SLOT3
149 &Spell::EffectSummonTotem, // 90 SPELL_EFFECT_SUMMON_TOTEM_SLOT4
150 &Spell::EffectUnused, // 91 SPELL_EFFECT_THREAT_ALL one spell: zzOLDBrainwash
151 &Spell::EffectEnchantHeldItem, // 92 SPELL_EFFECT_ENCHANT_HELD_ITEM
152 &Spell::EffectUnused, // 93 SPELL_EFFECT_SUMMON_PHANTASM
153 &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT
154 &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING
155 &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE
156 &Spell::EffectSummonCritter, // 97 SPELL_EFFECT_SUMMON_CRITTER
157 &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK
158 &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT
159 &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE
160 &Spell::EffectFeedPet, //101 SPELL_EFFECT_FEED_PET
161 &Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
162 &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
163 &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
164 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
165 &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
166 &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
167 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
168 &Spell::EffectSummonDeadPet, //109 SPELL_EFFECT_SUMMON_DEAD_PET
169 &Spell::EffectDestroyAllTotems, //110 SPELL_EFFECT_DESTROY_ALL_TOTEMS
170 &Spell::EffectDurabilityDamage, //111 SPELL_EFFECT_DURABILITY_DAMAGE
171 &Spell::EffectSummonDemon, //112 SPELL_EFFECT_SUMMON_DEMON
172 &Spell::EffectResurrectNew, //113 SPELL_EFFECT_RESURRECT_NEW
173 &Spell::EffectTaunt, //114 SPELL_EFFECT_ATTACK_ME
174 &Spell::EffectDurabilityDamagePCT, //115 SPELL_EFFECT_DURABILITY_DAMAGE_PCT
175 &Spell::EffectSkinPlayerCorpse, //116 SPELL_EFFECT_SKIN_PLAYER_CORPSE one spell: Remove Insignia, bg usage, required special corpse flags...
176 &Spell::EffectSpiritHeal, //117 SPELL_EFFECT_SPIRIT_HEAL one spell: Spirit Heal
177 &Spell::EffectSkill, //118 SPELL_EFFECT_SKILL professions and more
178 &Spell::EffectApplyAreaAura, //119 SPELL_EFFECT_APPLY_AREA_AURA_PET
179 &Spell::EffectUnused, //120 SPELL_EFFECT_TELEPORT_GRAVEYARD one spell: Graveyard Teleport Test
180 &Spell::EffectWeaponDmg, //121 SPELL_EFFECT_NORMALIZED_WEAPON_DMG
181 &Spell::EffectUnused, //122 SPELL_EFFECT_122 unused
182 &Spell::EffectSendTaxi, //123 SPELL_EFFECT_SEND_TAXI taxi/flight related (misc value is taxi path id)
183 &Spell::EffectPlayerPull, //124 SPELL_EFFECT_PLAYER_PULL opposite of knockback effect (pulls player twoard caster)
184 &Spell::EffectModifyThreatPercent, //125 SPELL_EFFECT_MODIFY_THREAT_PERCENT
185 &Spell::EffectStealBeneficialBuff, //126 SPELL_EFFECT_STEAL_BENEFICIAL_BUFF spell steal effect?
186 &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell
187 &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
188 &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
189 &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT
190 &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells
191 &Spell::EffectNULL, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value
192 &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization
193 &Spell::EffectKillCredit, //134 SPELL_EFFECT_KILL_CREDIT misc value is creature entry
194 &Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
195 &Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
196 &Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
197 &Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
198 &Spell::EffectUnused, //139 SPELL_EFFECT_139 unused
199 &Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
200 &Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
201 &Spell::EffectTriggerSpellWithValue, //142 SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
202 &Spell::EffectApplyAreaAura, //143 SPELL_EFFECT_APPLY_AREA_AURA_OWNER
203 &Spell::EffectNULL, //144 SPELL_EFFECT_144 Spectral Blast
204 &Spell::EffectNULL, //145 SPELL_EFFECT_145 Black Hole Effect
205 &Spell::EffectUnused, //146 SPELL_EFFECT_146 unused
206 &Spell::EffectQuestFail, //147 SPELL_EFFECT_QUEST_FAIL quest fail
207 &Spell::EffectUnused, //148 SPELL_EFFECT_148 unused
208 &Spell::EffectNULL, //149 SPELL_EFFECT_149 swoop
209 &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused
210 &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2
211 &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend
212 &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry
215 void Spell::EffectNULL(uint32 /*i*/)
217 sLog.outDebug("WORLD: Spell Effect DUMMY");
220 void Spell::EffectUnused(uint32 /*i*/)
222 // NOT USED BY ANY SPELL OR USELESS OR IMPLEMENTED IN DIFFERENT WAY IN MANGOS
225 void Spell::EffectResurrectNew(uint32 i)
227 if(!unitTarget || unitTarget->isAlive())
228 return;
230 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
231 return;
233 if(!unitTarget->IsInWorld())
234 return;
236 Player* pTarget = ((Player*)unitTarget);
238 if(pTarget->isRessurectRequested()) // already have one active request
239 return;
241 uint32 health = damage;
242 uint32 mana = m_spellInfo->EffectMiscValue[i];
243 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
244 SendResurrectRequest(pTarget);
247 void Spell::EffectInstaKill(uint32 /*i*/)
249 if( !unitTarget || !unitTarget->isAlive() )
250 return;
252 // Demonic Sacrifice
253 if(m_spellInfo->Id==18788 && unitTarget->GetTypeId()==TYPEID_UNIT)
255 uint32 entry = unitTarget->GetEntry();
256 uint32 spellID;
257 switch(entry)
259 case 416: spellID=18789; break; //imp
260 case 417: spellID=18792; break; //fellhunter
261 case 1860: spellID=18790; break; //void
262 case 1863: spellID=18791; break; //succubus
263 case 17252: spellID=35701; break; //fellguard
264 default:
265 sLog.outError("EffectInstaKill: Unhandled creature entry (%u) case.",entry);
266 return;
269 m_caster->CastSpell(m_caster,spellID,true);
272 if(m_caster==unitTarget) // prevent interrupt message
273 finish();
275 uint32 health = unitTarget->GetHealth();
276 m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
279 void Spell::EffectEnvirinmentalDMG(uint32 i)
281 uint32 absorb = 0;
282 uint32 resist = 0;
284 // Note: this hack with damage replace required until GO casting not implemented
285 // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support
286 // currently each enemy selected explicitly and self cast damage, we prevent apply self casted spell bonuses/etc
287 damage = m_spellInfo->EffectBasePoints[i]+m_spellInfo->EffectBaseDice[i];
289 m_caster->CalcAbsorbResist(m_caster,GetSpellSchoolMask(m_spellInfo), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
291 m_caster->SendSpellNonMeleeDamageLog(m_caster, m_spellInfo->Id, damage, GetSpellSchoolMask(m_spellInfo), absorb, resist, false, 0, false);
292 if(m_caster->GetTypeId() == TYPEID_PLAYER)
293 ((Player*)m_caster)->EnvironmentalDamage(m_caster->GetGUID(),DAMAGE_FIRE,damage);
296 void Spell::EffectSchoolDMG(uint32 effect_idx)
298 if( unitTarget && unitTarget->isAlive())
300 switch(m_spellInfo->SpellFamilyName)
302 case SPELLFAMILY_GENERIC:
304 //Gore
305 if(m_spellInfo->SpellIconID == 2269 )
307 damage+= rand()%2 ? damage : 0;
310 switch(m_spellInfo->Id) // better way to check unknown
312 // Meteor like spells (divided damage to targets)
313 case 24340: case 26558: case 28884: // Meteor
314 case 36837: case 38903: case 41276: // Meteor
315 case 26789: // Shard of the Fallen Star
316 case 31436: // Malevolent Cleave
317 case 35181: // Dive Bomb
318 case 40810: case 43267: case 43268: // Saber Lash
319 case 42384: // Brutal Swipe
320 case 45150: // Meteor Slash
322 uint32 count = 0;
323 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
324 if(ihit->effectMask & (1<<effect_idx))
325 ++count;
327 damage /= count; // divide to all targets
328 break;
330 // percent from health with min
331 case 25599: // Thundercrash
333 damage = unitTarget->GetHealth() / 2;
334 if(damage < 200)
335 damage = 200;
336 break;
339 break;
342 case SPELLFAMILY_MAGE:
344 // Arcane Blast
345 if(m_spellInfo->SpellFamilyFlags & 0x20000000LL)
347 m_caster->CastSpell(m_caster,36032,true);
349 break;
351 case SPELLFAMILY_WARRIOR:
353 // Bloodthirst
354 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
356 damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100);
358 // Shield Slam
359 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
360 damage += int32(m_caster->GetShieldBlockValue());
361 // Victory Rush
362 else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL)
364 damage = uint32(damage * m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
365 m_caster->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, false);
367 break;
369 case SPELLFAMILY_WARLOCK:
371 // Incinerate Rank 1 & 2
372 if((m_spellInfo->SpellFamilyFlags & 0x00004000000000LL) && m_spellInfo->SpellIconID==2128)
374 // Incinerate does more dmg (dmg*0.25) if the target is Immolated.
375 if(unitTarget->HasAuraState(AURA_STATE_IMMOLATE))
376 damage += int32(damage*0.25);
378 break;
380 case SPELLFAMILY_DRUID:
382 // Ferocious Bite
383 if((m_spellInfo->SpellFamilyFlags & 0x000800000) && m_spellInfo->SpellVisual==6587)
385 // converts each extra point of energy into ($f1+$AP/630) additional damage
386 float multiple = m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 630 + m_spellInfo->DmgMultiplier[effect_idx];
387 damage += int32(m_caster->GetPower(POWER_ENERGY) * multiple);
388 m_caster->SetPower(POWER_ENERGY,0);
390 // Rake
391 else if(m_spellInfo->SpellFamilyFlags & 0x0000000000001000LL)
393 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
395 // Swipe
396 else if(m_spellInfo->SpellFamilyFlags & 0x0010000000000000LL)
398 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.08f);
400 // Starfire
401 else if ( m_spellInfo->SpellFamilyFlags & 0x0004LL )
403 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
404 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
406 // Starfire Bonus (caster)
407 switch((*i)->GetModifier()->m_miscvalue)
409 case 5481: // Nordrassil Regalia - bonus
411 Unit::AuraList const& m_periodicDamageAuras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
412 for(Unit::AuraList::const_iterator itr = m_periodicDamageAuras.begin(); itr != m_periodicDamageAuras.end(); ++itr)
414 // Moonfire or Insect Swarm (target debuff from any casters)
415 if ( (*itr)->GetSpellProto()->SpellFamilyFlags & 0x00200002LL )
417 int32 mod = (*i)->GetModifier()->m_amount;
418 damage += damage*mod/100;
419 break;
422 break;
424 case 5148: //Improved Starfire - Ivory Idol of the Moongoddes Aura
426 damage += (*i)->GetModifier()->m_amount;
427 break;
432 //Mangle Bonus for the initial damage of Lacerate and Rake
433 if((m_spellInfo->SpellFamilyFlags==0x0000000000001000LL && m_spellInfo->SpellIconID==494) ||
434 (m_spellInfo->SpellFamilyFlags==0x0000010000000000LL && m_spellInfo->SpellIconID==2246))
436 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
437 for(Unit::AuraList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
438 if((*i)->GetSpellProto()->SpellFamilyFlags & 0x0000044000000000LL && (*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID)
440 damage = int32(damage*(100.0f+(*i)->GetModifier()->m_amount)/100.0f);
441 break;
444 break;
446 case SPELLFAMILY_ROGUE:
448 // Envenom
449 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x800000000LL))
451 // consume from stack dozes not more that have combo-points
452 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
454 // count consumed deadly poison doses at target
455 uint32 doses = 0;
457 // remove consumed poison doses
458 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
459 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end() && combo;)
461 // Deadly poison (only attacker applied)
462 if( (*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_ROGUE && ((*itr)->GetSpellProto()->SpellFamilyFlags & 0x10000) &&
463 (*itr)->GetSpellProto()->SpellVisual==5100 && (*itr)->GetCasterGUID()==m_caster->GetGUID() )
465 --combo;
466 ++doses;
468 unitTarget->RemoveSingleAuraFromStack((*itr)->GetId(), (*itr)->GetEffIndex());
470 itr = auras.begin();
472 else
473 ++itr;
476 damage *= doses;
477 damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.03f * doses);
479 // Eviscerate and Envenom Bonus Damage (item set effect)
480 if(m_caster->GetDummyAura(37169))
481 damage += ((Player*)m_caster)->GetComboPoints()*40;
484 // Eviscerate
485 else if((m_spellInfo->SpellFamilyFlags & 0x00020000LL) && m_caster->GetTypeId()==TYPEID_PLAYER)
487 if(uint32 combo = ((Player*)m_caster)->GetComboPoints())
489 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * combo * 0.03f);
491 // Eviscerate and Envenom Bonus Damage (item set effect)
492 if(m_caster->GetDummyAura(37169))
493 damage += combo*40;
496 break;
498 case SPELLFAMILY_HUNTER:
500 // Mongoose Bite
501 if((m_spellInfo->SpellFamilyFlags & 0x000000002) && m_spellInfo->SpellVisual==342)
503 damage += int32(m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2);
505 // Arcane Shot
506 else if((m_spellInfo->SpellFamilyFlags & 0x00000800) && m_spellInfo->maxLevel > 0)
508 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.15);
510 // Steady Shot
511 else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
513 int32 base = irand((int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),(int32)m_caster->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE));
514 damage += int32(float(base)/m_caster->GetAttackTime(RANGED_ATTACK)*2800 + m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.2f);
516 //Explosive Trap Effect
517 else if(m_spellInfo->SpellFamilyFlags & 0x00000004)
519 damage += int32(m_caster->GetTotalAttackPowerValue(RANGED_ATTACK)*0.1);
521 break;
523 case SPELLFAMILY_PALADIN:
525 //Judgement of Vengeance
526 if((m_spellInfo->SpellFamilyFlags & 0x800000000LL) && m_spellInfo->SpellIconID==2292)
528 uint32 stacks = 0;
529 Unit::AuraList const& auras = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
530 for(Unit::AuraList::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
531 if((*itr)->GetId() == 31803 && (*itr)->GetCasterGUID()==m_caster->GetGUID())
532 ++stacks;
533 if(!stacks)
534 //No damage if the target isn't affected by this
535 damage = -1;
536 else
537 damage *= stacks;
539 break;
543 if(damage >= 0)
545 uint32 finalDamage;
546 if(m_originalCaster) // m_caster only passive source of cast
547 finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
548 else
549 finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
551 // post effects
552 switch(m_spellInfo->SpellFamilyName)
554 case SPELLFAMILY_WARRIOR:
556 // Bloodthirst
557 if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
559 uint32 BTAura = 0;
560 switch(m_spellInfo->Id)
562 case 23881: BTAura = 23885; break;
563 case 23892: BTAura = 23886; break;
564 case 23893: BTAura = 23887; break;
565 case 23894: BTAura = 23888; break;
566 case 25251: BTAura = 25252; break;
567 case 30335: BTAura = 30339; break;
568 default:
569 sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
570 break;
573 if (BTAura)
574 m_caster->CastSpell(m_caster,BTAura,true);
576 break;
578 case SPELLFAMILY_PRIEST:
580 // Shadow Word: Death
581 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
582 // deals damage equal to damage done to caster if victim is not killed
583 m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
585 break;
587 case SPELLFAMILY_PALADIN:
589 // Judgement of Blood
590 if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
592 int32 damagePoint = finalDamage * 33 / 100;
593 m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
595 break;
602 void Spell::EffectDummy(uint32 i)
604 if(!unitTarget && !gameObjTarget && !itemTarget)
605 return;
607 // selection by spell family
608 switch(m_spellInfo->SpellFamilyName)
610 case SPELLFAMILY_GENERIC:
611 // Gnomish Poultryizer trinket
612 switch(m_spellInfo->Id )
614 case 8063: // Deviate Fish
616 if(m_caster->GetTypeId() != TYPEID_PLAYER)
617 return;
619 uint32 spell_id = 0;
620 switch(urand(1,5))
622 case 1: spell_id = 8064; break; // Sleepy
623 case 2: spell_id = 8065; break; // Invigorate
624 case 3: spell_id = 8066; break; // Shrink
625 case 4: spell_id = 8067; break; // Party Time!
626 case 5: spell_id = 8068; break; // Healthy Spirit
628 m_caster->CastSpell(m_caster,spell_id,true,NULL);
629 return;
631 case 8213: // Savory Deviate Delight
633 if(m_caster->GetTypeId() != TYPEID_PLAYER)
634 return;
636 uint32 spell_id = 0;
637 switch(urand(1,2))
639 // Flip Out - ninja
640 case 1: spell_id = (m_caster->getGender() == GENDER_MALE ? 8219 : 8220); break;
641 // Yaaarrrr - pirate
642 case 2: spell_id = (m_caster->getGender() == GENDER_MALE ? 8221 : 8222); break;
644 m_caster->CastSpell(m_caster,spell_id,true,NULL);
645 return;
647 case 8593: // Symbol of life (restore creature to life)
648 case 31225: // Shimmering Vessel (restore creature to life)
650 if(!unitTarget || unitTarget->GetTypeId()!=TYPEID_UNIT)
651 return;
652 ((Creature*)unitTarget)->setDeathState(JUST_ALIVED);
653 return;
655 case 12162: // Deep wounds
656 case 12850: // (now good common check for this spells)
657 case 12868:
659 if(!unitTarget)
660 return;
662 float damage;
663 // DW should benefit of attack power, damage percent mods etc.
664 // TODO: check if using offhand damage is correct and if it should be divided by 2
665 if (m_caster->haveOffhandWeapon() && m_caster->getAttackTimer(BASE_ATTACK) > m_caster->getAttackTimer(OFF_ATTACK))
666 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE))/2;
667 else
668 damage = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE))/2;
670 switch (m_spellInfo->Id)
672 case 12850: damage *= 0.2f; break;
673 case 12162: damage *= 0.4f; break;
674 case 12868: damage *= 0.6f; break;
675 default:
676 sLog.outError("Spell::EffectDummy: Spell %u not handled in DW",m_spellInfo->Id);
677 return;
680 int32 deepWoundsDotBasePoints0 = int32(damage / 4);
681 m_caster->CastCustomSpell(unitTarget, 12721, &deepWoundsDotBasePoints0, NULL, NULL, true, NULL);
682 return;
684 case 12975: //Last Stand
686 int32 healthModSpellBasePoints0 = int32(m_caster->GetMaxHealth()*0.3);
687 m_caster->CastCustomSpell(m_caster, 12976, &healthModSpellBasePoints0, NULL, NULL, true, NULL);
688 return;
690 case 13120: // net-o-matic
692 if(!unitTarget)
693 return;
695 uint32 spell_id = 0;
697 uint32 roll = urand(0, 99);
699 if(roll < 2) // 2% for 30 sec self root (off-like chance unknown)
700 spell_id = 16566;
701 else if(roll < 4) // 2% for 20 sec root, charge to target (off-like chance unknown)
702 spell_id = 13119;
703 else // normal root
704 spell_id = 13099;
706 m_caster->CastSpell(unitTarget,spell_id,true,NULL);
707 return;
709 case 13567: // Dummy Trigger
711 // can be used for different aura triggreing, so select by aura
712 if(!m_triggeredByAuraSpell || !unitTarget)
713 return;
715 switch(m_triggeredByAuraSpell->Id)
717 case 26467: // Persistent Shield
718 m_caster->CastCustomSpell(unitTarget, 26470, &damage, NULL, NULL, true);
719 break;
720 default:
721 sLog.outError("EffectDummy: Non-handled case for spell 13567 for triggered aura %u",m_triggeredByAuraSpell->Id);
722 break;
724 return;
726 case 14185: // Preparation Rogue
728 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
729 return;
731 //immediately finishes the cooldown on certain Rogue abilities
732 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
733 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
735 uint32 classspell = itr->first;
736 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
738 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags & 0x26000000860LL))
740 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
742 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
743 data << uint32(classspell);
744 data << uint64(m_caster->GetGUID());
745 ((Player*)m_caster)->GetSession()->SendPacket(&data);
748 return;
750 case 15998: // Capture Worg Pup
751 case 29435: // Capture Female Kaliri Hatchling
753 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
754 return;
756 Creature* creatureTarget = (Creature*)unitTarget;
757 creatureTarget->setDeathState(JUST_DIED);
758 creatureTarget->RemoveCorpse();
759 creatureTarget->SetHealth(0); // just for nice GM-mode view
760 return;
762 case 16589: // Noggenfogger Elixir
764 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
765 return;
767 uint32 spell_id = 0;
768 switch(urand(1,3))
770 case 1: spell_id = 16595; break;
771 case 2: spell_id = 16593; break;
772 default:spell_id = 16591; break;
775 m_caster->CastSpell(m_caster,spell_id,true,NULL);
776 return;
778 case 17251: // Spirit Healer Res
780 if(!unitTarget || !m_originalCaster)
781 return;
783 if(m_originalCaster->GetTypeId() == TYPEID_PLAYER)
785 WorldPacket data(SMSG_SPIRIT_HEALER_CONFIRM, 8);
786 data << unitTarget->GetGUID();
787 ((Player*)m_originalCaster)->GetSession()->SendPacket( &data );
789 return;
791 case 17271: // Test Fetid Skull
793 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
794 return;
796 uint32 spell_id = roll_chance_i(50) ? 17269 : 17270;
798 m_caster->CastSpell(m_caster,spell_id,true,NULL);
799 return;
801 case 20577: // Cannibalize
802 if (unitTarget)
803 m_caster->CastSpell(m_caster,20578,false,NULL);
804 return;
805 case 23019: // Crystal Prison Dummy DND
807 if(!unitTarget || !unitTarget->isAlive() || unitTarget->GetTypeId() != TYPEID_UNIT || ((Creature*)unitTarget)->isPet())
808 return;
810 Creature* creatureTarget = (Creature*)unitTarget;
811 if(creatureTarget->isPet())
812 return;
814 creatureTarget->setDeathState(JUST_DIED);
815 creatureTarget->RemoveCorpse();
816 creatureTarget->SetHealth(0); // just for nice GM-mode view
818 GameObject* pGameObj = new GameObject;
820 Map *map = creatureTarget->GetMap();
822 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), 179644, map,
823 creatureTarget->GetPositionX(), creatureTarget->GetPositionY(), creatureTarget->GetPositionZ(),
824 creatureTarget->GetOrientation(), 0, 0, 0, 0, 100, 1) )
826 delete pGameObj;
827 return;
830 pGameObj->SetRespawnTime(creatureTarget->GetRespawnTime()-time(NULL));
831 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
832 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
833 pGameObj->SetSpellId(m_spellInfo->Id);
835 DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n");
836 map->Add(pGameObj);
838 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
839 data << uint64(pGameObj->GetGUID());
840 m_caster->SendMessageToSet(&data,true);
842 return;
844 case 23074: // Arc. Dragonling
845 if (!m_CastItem) return;
846 m_caster->CastSpell(m_caster,19804,true,m_CastItem);
847 return;
848 case 23075: // Mithril Mechanical Dragonling
849 if (!m_CastItem) return;
850 m_caster->CastSpell(m_caster,12749,true,m_CastItem);
851 return;
852 case 23076: // Mechanical Dragonling
853 if (!m_CastItem) return;
854 m_caster->CastSpell(m_caster,4073,true,m_CastItem);
855 return;
856 case 23133: // Gnomish Battle Chicken
857 if (!m_CastItem) return;
858 m_caster->CastSpell(m_caster,13166,true,m_CastItem);
859 return;
860 case 23448: // Ultrasafe Transporter: Gadgetzan - backfires
862 int32 r = irand(0, 119);
863 if ( r < 20 ) // 1/6 polymorph
864 m_caster->CastSpell(m_caster,23444,true);
865 else if ( r < 100 ) // 4/6 evil twin
866 m_caster->CastSpell(m_caster,23445,true);
867 else // 1/6 miss the target
868 m_caster->CastSpell(m_caster,36902,true);
869 return;
871 case 23453: // Ultrasafe Transporter: Gadgetzan
872 if ( roll_chance_i(50) ) // success
873 m_caster->CastSpell(m_caster,23441,true);
874 else // failure
875 m_caster->CastSpell(m_caster,23446,true);
876 return;
877 case 23645: // Hourglass Sand
878 m_caster->RemoveAurasDueToSpell(23170);
879 return;
880 case 23725: // Gift of Life (warrior bwl trinket)
881 m_caster->CastSpell(m_caster,23782,true);
882 m_caster->CastSpell(m_caster,23783,true);
883 return;
884 case 25860: // Reindeer Transformation
886 if (!m_caster->HasAuraType(SPELL_AURA_MOUNTED))
887 return;
889 float flyspeed = m_caster->GetSpeedRate(MOVE_FLY);
890 float speed = m_caster->GetSpeedRate(MOVE_RUN);
892 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
894 //5 different spells used depending on mounted speed and if mount can fly or not
895 if (flyspeed >= 4.1f)
896 m_caster->CastSpell(m_caster, 44827, true); //310% flying Reindeer
897 else if (flyspeed >= 3.8f)
898 m_caster->CastSpell(m_caster, 44825, true); //280% flying Reindeer
899 else if (flyspeed >= 1.6f)
900 m_caster->CastSpell(m_caster, 44824, true); //60% flying Reindeer
901 else if (speed >= 2.0f)
902 m_caster->CastSpell(m_caster, 25859, true); //100% ground Reindeer
903 else
904 m_caster->CastSpell(m_caster, 25858, true); //60% ground Reindeer
906 return;
908 //case 26074: // Holiday Cheer
909 // return; -- implemented at client side
910 case 28006: // Arcane Cloaking
912 if( unitTarget->GetTypeId() == TYPEID_PLAYER )
913 m_caster->CastSpell(unitTarget,29294,true);
914 return;
916 case 28730: // Arcane Torrent (Mana)
918 int32 count = 0;
919 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
920 for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
921 if ((*i)->GetId() == 28734)
922 ++count;
923 if (count)
925 m_caster->RemoveAurasDueToSpell(28734);
926 int32 bp = damage * count;
927 m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
929 return;
931 case 29200: // Purify Helboar Meat
933 if( m_caster->GetTypeId() != TYPEID_PLAYER )
934 return;
936 uint32 spell_id = roll_chance_i(50) ? 29277 : 29278;
938 m_caster->CastSpell(m_caster,spell_id,true,NULL);
939 return;
941 case 29858: // Soulshatter
942 if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
943 m_caster->CastSpell(unitTarget,32835,true);
944 return;
945 case 30458: // Nigh Invulnerability
946 if (!m_CastItem) return;
947 if(roll_chance_i(86)) // success
948 m_caster->CastSpell(m_caster, 30456, true, m_CastItem);
949 else // backfire in 14% casts
950 m_caster->CastSpell(m_caster, 30457, true, m_CastItem);
951 return;
952 case 30507: // Poultryizer
953 if (!m_CastItem) return;
954 if(roll_chance_i(80)) // success
955 m_caster->CastSpell(unitTarget, 30501, true, m_CastItem);
956 else // backfire 20%
957 m_caster->CastSpell(unitTarget, 30504, true, m_CastItem);
958 return;
959 case 33060: // Make a Wish
961 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
962 return;
964 uint32 spell_id = 0;
966 switch(urand(1,5))
968 case 1: spell_id = 33053; break;
969 case 2: spell_id = 33057; break;
970 case 3: spell_id = 33059; break;
971 case 4: spell_id = 33062; break;
972 case 5: spell_id = 33064; break;
975 m_caster->CastSpell(m_caster,spell_id,true,NULL);
976 return;
978 case 35745:
980 uint32 spell_id;
981 switch(m_caster->GetAreaId())
983 case 3900: spell_id = 35743; break;
984 case 3742: spell_id = 35744; break;
985 default: return;
988 m_caster->CastSpell(m_caster,spell_id,true);
989 return;
991 case 37674: // Chaos Blast
992 if(unitTarget)
993 m_caster->CastSpell(unitTarget,37675,true);
994 return;
995 case 44875: // Complete Raptor Capture
997 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
998 return;
1000 Creature* creatureTarget = (Creature*)unitTarget;
1002 creatureTarget->setDeathState(JUST_DIED);
1003 creatureTarget->RemoveCorpse();
1004 creatureTarget->SetHealth(0); // just for nice GM-mode view
1006 //cast spell Raptor Capture Credit
1007 m_caster->CastSpell(m_caster,42337,true,NULL);
1008 return;
1010 case 37573: //Temporal Phase Modulator
1012 if(!unitTarget)
1013 return;
1015 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1016 if(!tempSummon)
1017 return;
1019 uint32 health = tempSummon->GetHealth();
1020 const uint32 entry_list[6] = {21821, 21820, 21817};
1022 float x = tempSummon->GetPositionX();
1023 float y = tempSummon->GetPositionY();
1024 float z = tempSummon->GetPositionZ();
1025 float o = tempSummon->GetOrientation();
1027 tempSummon->UnSummon();
1029 Creature* pCreature = m_caster->SummonCreature(entry_list[urand(0, 2)], x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1030 if (!pCreature)
1031 return;
1033 pCreature->SetHealth(health);
1035 if(pCreature->AI())
1036 pCreature->AI()->AttackStart(m_caster);
1038 return;
1040 case 34665: //Administer Antidote
1042 if(!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER )
1043 return;
1045 if(!unitTarget)
1046 return;
1048 TemporarySummon* tempSummon = dynamic_cast<TemporarySummon*>(unitTarget);
1049 if(!tempSummon)
1050 return;
1052 uint32 health = tempSummon->GetHealth();
1054 float x = tempSummon->GetPositionX();
1055 float y = tempSummon->GetPositionY();
1056 float z = tempSummon->GetPositionZ();
1057 float o = tempSummon->GetOrientation();
1058 tempSummon->UnSummon();
1060 Creature* pCreature = m_caster->SummonCreature(16992, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,180000);
1061 if (!pCreature)
1062 return;
1064 pCreature->SetHealth(health);
1065 ((Player*)m_caster)->KilledMonster(16992,pCreature->GetGUID());
1067 if (pCreature->AI())
1068 pCreature->AI()->AttackStart(m_caster);
1070 return;
1072 case 44997: // Converting Sentry
1074 //Converted Sentry Credit
1075 m_caster->CastSpell(m_caster, 45009, true);
1076 return;
1078 case 45030: // Impale Emissary
1080 // Emissary of Hate Credit
1081 m_caster->CastSpell(m_caster, 45088, true);
1082 return;
1084 case 50243: // Teach Language
1086 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1087 return;
1089 // spell has a 1/3 chance to trigger one of the below
1090 if(roll_chance_i(66))
1091 return;
1092 if(((Player*)m_caster)->GetTeam() == ALLIANCE)
1094 // 1000001 - gnomish binary
1095 m_caster->CastSpell(m_caster, 50242, true);
1097 else
1099 // 01001000 - goblin binary
1100 m_caster->CastSpell(m_caster, 50246, true);
1103 return;
1105 case 51582: //Rocket Boots Engaged (Rocket Boots Xtreme and Rocket Boots Xtreme Lite)
1107 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1108 return;
1110 if(BattleGround* bg = ((Player*)m_caster)->GetBattleGround())
1111 bg->EventPlayerDroppedFlag((Player*)m_caster);
1113 m_caster->CastSpell(m_caster, 30452, true, NULL);
1114 return;
1118 //All IconID Check in there
1119 switch(m_spellInfo->SpellIconID)
1121 // Berserking (troll racial traits)
1122 case 1661:
1124 uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100);
1125 int32 melee_mod = 10;
1126 if (healthPerc <= 40)
1127 melee_mod = 30;
1128 if (healthPerc < 100 && healthPerc > 40)
1129 melee_mod = 10+(100-healthPerc)/3;
1131 int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1
1132 int32 hasteModBasePoints1 = (5-melee_mod);
1133 int32 hasteModBasePoints2 = 5;
1135 // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway
1136 m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true);
1137 m_caster->CastCustomSpell(m_caster,26635,&hasteModBasePoints0,&hasteModBasePoints1,&hasteModBasePoints2,true,NULL);
1138 return;
1141 break;
1142 case SPELLFAMILY_MAGE:
1143 switch(m_spellInfo->Id )
1145 case 11958: // Cold Snap
1147 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1148 return;
1150 // immediately finishes the cooldown on Frost spells
1151 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1152 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1154 if (itr->second->state == PLAYERSPELL_REMOVED)
1155 continue;
1157 uint32 classspell = itr->first;
1158 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1160 if( spellInfo->SpellFamilyName == SPELLFAMILY_MAGE &&
1161 (GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
1162 spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
1164 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1166 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1167 data << uint32(classspell);
1168 data << uint64(m_caster->GetGUID());
1169 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1172 return;
1174 case 32826:
1176 if ( unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT )
1178 //Polymorph Cast Visual Rank 1
1179 const uint32 spell_list[6] = {32813, 32816, 32817, 32818, 32819, 32820};
1180 unitTarget->CastSpell( unitTarget, spell_list[urand(0, 5)], true);
1182 return;
1185 break;
1186 case SPELLFAMILY_WARRIOR:
1187 // Charge
1188 if(m_spellInfo->SpellFamilyFlags & 0x1 && m_spellInfo->SpellVisual == 867)
1190 int32 chargeBasePoints0 = damage;
1191 m_caster->CastCustomSpell(m_caster,34846,&chargeBasePoints0,NULL,NULL,true);
1192 return;
1194 // Execute
1195 if(m_spellInfo->SpellFamilyFlags & 0x20000000)
1197 if(!unitTarget)
1198 return;
1200 int32 basePoints0 = damage+int32(m_caster->GetPower(POWER_RAGE) * m_spellInfo->DmgMultiplier[i]);
1201 m_caster->CastCustomSpell(unitTarget, 20647, &basePoints0, NULL, NULL, true, 0);
1202 m_caster->SetPower(POWER_RAGE,0);
1203 return;
1205 if(m_spellInfo->Id==21977) //Warrior's Wrath
1207 if(!unitTarget)
1208 return;
1210 m_caster->CastSpell(unitTarget,21887,true); // spell mod
1211 return;
1213 break;
1214 case SPELLFAMILY_WARLOCK:
1215 //Life Tap (only it have this with dummy effect)
1216 if (m_spellInfo->SpellFamilyFlags == 0x40000)
1218 float cost = m_currentBasePoints[0]+1;
1220 if(Player* modOwner = m_caster->GetSpellModOwner())
1221 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, cost,this);
1223 int32 dmg = m_caster->SpellDamageBonus(m_caster, m_spellInfo,uint32(cost > 0 ? cost : 0), SPELL_DIRECT_DAMAGE);
1225 if(int32(m_caster->GetHealth()) > dmg)
1227 // Shouldn't Appear in Combat Log
1228 m_caster->ModifyHealth(-dmg);
1230 int32 mana = dmg;
1232 Unit::AuraList const& auraDummy = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
1233 for(Unit::AuraList::const_iterator itr = auraDummy.begin(); itr != auraDummy.end(); ++itr)
1235 // only Imp. Life Tap have this in combination with dummy aura
1236 if((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (*itr)->GetSpellProto()->SpellIconID == 208)
1237 mana = ((*itr)->GetModifier()->m_amount + 100)* mana / 100;
1240 m_caster->CastCustomSpell(m_caster,31818,&mana,NULL,NULL,true,NULL);
1242 // Mana Feed
1243 int32 manaFeedVal = m_caster->CalculateSpellDamage(m_spellInfo,1, m_spellInfo->EffectBasePoints[1],m_caster);
1244 manaFeedVal = manaFeedVal * mana / 100;
1245 if(manaFeedVal > 0)
1246 m_caster->CastCustomSpell(m_caster,32553,&manaFeedVal,NULL,NULL,true,NULL);
1248 else
1249 SendCastResult(SPELL_FAILED_FIZZLE);
1250 return;
1252 break;
1253 case SPELLFAMILY_PRIEST:
1254 switch(m_spellInfo->Id )
1256 case 28598: // Touch of Weakness triggered spell
1258 if(!unitTarget || !m_triggeredByAuraSpell)
1259 return;
1261 uint32 spellid = 0;
1262 switch(m_triggeredByAuraSpell->Id)
1264 case 2652: spellid = 2943; break; // Rank 1
1265 case 19261: spellid = 19249; break; // Rank 2
1266 case 19262: spellid = 19251; break; // Rank 3
1267 case 19264: spellid = 19252; break; // Rank 4
1268 case 19265: spellid = 19253; break; // Rank 5
1269 case 19266: spellid = 19254; break; // Rank 6
1270 case 25461: spellid = 25460; break; // Rank 7
1271 default:
1272 sLog.outError("Spell::EffectDummy: Spell 28598 triggered by unhandeled spell %u",m_triggeredByAuraSpell->Id);
1273 return;
1275 m_caster->CastSpell(unitTarget, spellid, true, NULL);
1276 return;
1279 break;
1280 case SPELLFAMILY_DRUID:
1281 switch(m_spellInfo->Id )
1283 case 5420: // Tree of Life passive
1285 // Tree of Life area effect
1286 int32 health_mod = int32(m_caster->GetStat(STAT_SPIRIT)/4);
1287 m_caster->CastCustomSpell(m_caster,34123,&health_mod,NULL,NULL,true,NULL);
1288 return;
1291 break;
1292 case SPELLFAMILY_ROGUE:
1293 switch(m_spellInfo->Id )
1295 case 31231: // Cheat Death
1297 m_caster->CastSpell(m_caster,45182,true);
1298 return;
1300 case 5938: // Shiv
1302 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1303 return;
1305 Player *pCaster = ((Player*)m_caster);
1307 Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK);
1308 if(!item)
1309 return;
1311 // all poison enchantments is temporary
1312 uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT);
1313 if(!enchant_id)
1314 return;
1316 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
1317 if(!pEnchant)
1318 return;
1320 for (int s=0;s<3;s++)
1322 if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
1323 continue;
1325 SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]);
1326 if(!combatEntry || combatEntry->Dispel != DISPEL_POISON)
1327 continue;
1329 m_caster->CastSpell(unitTarget, combatEntry, true, item);
1332 m_caster->CastSpell(unitTarget, 5940, true);
1333 return;
1336 break;
1337 case SPELLFAMILY_HUNTER:
1338 // Steady Shot
1339 if(m_spellInfo->SpellFamilyFlags & 0x100000000LL)
1341 if( !unitTarget || !unitTarget->isAlive())
1342 return;
1344 bool found = false;
1346 // check dazed affect
1347 Unit::AuraList const& decSpeedList = unitTarget->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
1348 for(Unit::AuraList::const_iterator iter = decSpeedList.begin(); iter != decSpeedList.end(); ++iter)
1350 if((*iter)->GetSpellProto()->SpellIconID==15 && (*iter)->GetSpellProto()->Dispel==0)
1352 found = true;
1353 break;
1357 if(found)
1358 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
1359 return;
1361 // Kill command
1362 if(m_spellInfo->SpellFamilyFlags & 0x00080000000000LL)
1364 if(m_caster->getClass()!=CLASS_HUNTER)
1365 return;
1367 // clear hunter crit aura state
1368 m_caster->ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE,false);
1370 // additional damage from pet to pet target
1371 Pet* pet = m_caster->GetPet();
1372 if(!pet || !pet->getVictim())
1373 return;
1375 uint32 spell_id = 0;
1376 switch (m_spellInfo->Id)
1378 case 34026: spell_id = 34027; break; // rank 1
1379 default:
1380 sLog.outError("Spell::EffectDummy: Spell %u not handled in KC",m_spellInfo->Id);
1381 return;
1384 pet->CastSpell(pet->getVictim(), spell_id, true);
1385 return;
1388 switch(m_spellInfo->Id)
1390 case 23989: //Readiness talent
1392 if(m_caster->GetTypeId()!=TYPEID_PLAYER)
1393 return;
1395 //immediately finishes the cooldown for hunter abilities
1396 const PlayerSpellMap& sp_list = ((Player *)m_caster)->GetSpellMap();
1397 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1399 uint32 classspell = itr->first;
1400 SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
1402 if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
1404 ((Player*)m_caster)->RemoveSpellCooldown(classspell);
1406 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1407 data << uint32(classspell);
1408 data << uint64(m_caster->GetGUID());
1409 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1412 return;
1414 case 37506: // Scatter Shot
1416 if (m_caster->GetTypeId()!=TYPEID_PLAYER)
1417 return;
1419 // break Auto Shot and autohit
1420 m_caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL);
1421 m_caster->AttackStop();
1422 ((Player*)m_caster)->SendAttackSwingCancelAttack();
1423 return;
1426 break;
1427 case SPELLFAMILY_PALADIN:
1428 switch(m_spellInfo->SpellIconID)
1430 case 156: // Holy Shock
1432 if(!unitTarget)
1433 return;
1435 int hurt = 0;
1436 int heal = 0;
1438 switch(m_spellInfo->Id)
1440 case 20473: hurt = 25912; heal = 25914; break;
1441 case 20929: hurt = 25911; heal = 25913; break;
1442 case 20930: hurt = 25902; heal = 25903; break;
1443 case 27174: hurt = 27176; heal = 27175; break;
1444 case 33072: hurt = 33073; heal = 33074; break;
1445 default:
1446 sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id);
1447 return;
1450 if(m_caster->IsFriendlyTo(unitTarget))
1451 m_caster->CastSpell(unitTarget, heal, true, 0);
1452 else
1453 m_caster->CastSpell(unitTarget, hurt, true, 0);
1455 return;
1457 case 561: // Judgement of command
1459 if(!unitTarget)
1460 return;
1462 uint32 spell_id = m_currentBasePoints[i]+1;
1463 SpellEntry const* spell_proto = sSpellStore.LookupEntry(spell_id);
1464 if(!spell_proto)
1465 return;
1467 if( !unitTarget->hasUnitState(UNIT_STAT_STUNNED) && m_caster->GetTypeId()==TYPEID_PLAYER)
1469 // decreased damage (/2) for non-stunned target.
1470 SpellModifier *mod = new SpellModifier;
1471 mod->op = SPELLMOD_DAMAGE;
1472 mod->value = -50;
1473 mod->type = SPELLMOD_PCT;
1474 mod->spellId = m_spellInfo->Id;
1475 mod->effectId = i;
1476 mod->lastAffected = NULL;
1477 mod->mask = 0x0000020000000000LL;
1478 mod->charges = 0;
1480 ((Player*)m_caster)->AddSpellMod(mod, true);
1481 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1482 // mod deleted
1483 ((Player*)m_caster)->AddSpellMod(mod, false);
1485 else
1486 m_caster->CastSpell(unitTarget,spell_proto,true,NULL);
1488 return;
1492 switch(m_spellInfo->Id)
1494 case 31789: // Righteous Defense (step 1)
1496 // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target)
1498 // non-standard cast requirement check
1499 if (!unitTarget || unitTarget->getAttackers().empty())
1501 // clear cooldown at fail
1502 if(m_caster->GetTypeId()==TYPEID_PLAYER)
1504 ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
1506 WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
1507 data << uint32(m_spellInfo->Id);
1508 data << uint64(m_caster->GetGUID());
1509 ((Player*)m_caster)->GetSession()->SendPacket(&data);
1512 SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
1513 return;
1516 // Righteous Defense (step 2) (in old version 31980 dummy effect)
1517 // Clear targets for eff 1
1518 for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
1519 ihit->effectMask &= ~(1<<1);
1521 // not empty (checked)
1522 Unit::AttackerSet const& attackers = unitTarget->getAttackers();
1524 // chance to be selected from list
1525 float chance = 100.0f/attackers.size();
1526 uint32 count=0;
1527 for(Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr)
1529 if(!roll_chance_f(chance))
1530 continue;
1531 ++count;
1532 AddUnitTarget((*aItr), 1);
1535 // now let next effect cast spell at each target.
1536 return;
1538 case 37877: // Blessing of Faith
1540 if(!unitTarget)
1541 return;
1543 uint32 spell_id = 0;
1544 switch(unitTarget->getClass())
1546 case CLASS_DRUID: spell_id = 37878; break;
1547 case CLASS_PALADIN: spell_id = 37879; break;
1548 case CLASS_PRIEST: spell_id = 37880; break;
1549 case CLASS_SHAMAN: spell_id = 37881; break;
1550 default: return; // ignore for not healing classes
1553 m_caster->CastSpell(m_caster,spell_id,true);
1554 return;
1557 break;
1558 case SPELLFAMILY_SHAMAN:
1559 //Shaman Rockbiter Weapon
1560 if (m_spellInfo->SpellFamilyFlags == 0x400000)
1562 uint32 spell_id = 0;
1563 switch(m_spellInfo->Id)
1565 case 8017: spell_id = 36494; break; // Rank 1
1566 case 8018: spell_id = 36750; break; // Rank 2
1567 case 8019: spell_id = 36755; break; // Rank 3
1568 case 10399: spell_id = 36759; break; // Rank 4
1569 case 16314: spell_id = 36763; break; // Rank 5
1570 case 16315: spell_id = 36766; break; // Rank 6
1571 case 16316: spell_id = 36771; break; // Rank 7
1572 case 25479: spell_id = 36775; break; // Rank 8
1573 case 25485: spell_id = 36499; break; // Rank 9
1574 default:
1575 sLog.outError("Spell::EffectDummy: Spell %u not handled in RW",m_spellInfo->Id);
1576 return;
1579 SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id );
1581 if(!spellInfo)
1583 sLog.outError("WORLD: unknown spell id %i\n", spell_id);
1584 return;
1587 if(m_caster->GetTypeId() != TYPEID_PLAYER)
1588 return;
1590 for(int i = BASE_ATTACK; i <= OFF_ATTACK; ++i)
1592 if(Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(i)))
1594 if(item->IsFitToSpellRequirements(m_spellInfo))
1596 Spell *spell = new Spell(m_caster, spellInfo, true);
1598 // enchanting spell selected by calculated damage-per-sec in enchanting effect
1599 // at calculation applied affect from Elemental Weapons talent
1600 // real enchantment damage-1
1601 spell->m_currentBasePoints[1] = damage-1;
1603 SpellCastTargets targets;
1604 targets.setItemTarget( item );
1605 spell->prepare(&targets);
1609 return;
1612 if(m_spellInfo->Id == 39610) // Mana-Tide Totem effect
1614 if(!unitTarget || unitTarget->getPowerType() != POWER_MANA)
1615 return;
1617 // Regenerate 6% of Total Mana Every 3 secs
1618 int32 EffectBasePoints0 = unitTarget->GetMaxPower(POWER_MANA) * damage / 100;
1619 m_caster->CastCustomSpell(unitTarget,39609,&EffectBasePoints0,NULL,NULL,true,NULL,NULL,m_originalCasterGUID);
1620 return;
1623 break;
1626 // pet auras
1627 if(PetAura const* petSpell = spellmgr.GetPetAura(m_spellInfo->Id))
1629 m_caster->AddPetAura(petSpell);
1630 return;
1634 void Spell::EffectTriggerSpellWithValue(uint32 i)
1636 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1638 // normal case
1639 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1641 if(!spellInfo)
1643 sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id);
1644 return;
1647 int32 bp = damage;
1648 m_caster->CastCustomSpell(unitTarget,triggered_spell_id,&bp,&bp,&bp,true,NULL,NULL,m_originalCasterGUID);
1651 void Spell::EffectTriggerRitualOfSummoning(uint32 i)
1653 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1654 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1656 if(!spellInfo)
1658 sLog.outError("EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1659 return;
1662 finish();
1663 Spell *spell = new Spell(m_caster, spellInfo, true);
1665 SpellCastTargets targets;
1666 targets.setUnitTarget( unitTarget);
1667 spell->prepare(&targets);
1669 m_caster->SetCurrentCastedSpell(spell);
1670 spell->m_selfContainer = &(m_caster->m_currentSpells[spell->GetCurrentContainer()]);
1674 void Spell::EffectForceCast(uint32 i)
1676 if( !unitTarget )
1677 return;
1679 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1681 // normal case
1682 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1684 if(!spellInfo)
1686 sLog.outError("EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1687 return;
1690 unitTarget->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
1693 void Spell::EffectTriggerSpell(uint32 i)
1695 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i];
1697 // special cases
1698 switch(triggered_spell_id)
1700 // Vanish
1701 case 18461:
1703 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
1704 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
1705 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
1707 // if this spell is given to NPC it must handle rest by it's own AI
1708 if ( m_caster->GetTypeId() != TYPEID_PLAYER )
1709 return;
1711 // get highest rank of the Stealth spell
1712 uint32 spellId = 0;
1713 const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
1714 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
1716 // only highest rank is shown in spell book, so simply check if shown in spell book
1717 if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
1718 continue;
1720 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
1721 if (!spellInfo)
1722 continue;
1724 if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_STEALTH)
1726 spellId = spellInfo->Id;
1727 break;
1731 // no Stealth spell found
1732 if (!spellId)
1733 return;
1735 // reset cooldown on it if needed
1736 if(((Player*)m_caster)->HasSpellCooldown(spellId))
1737 ((Player*)m_caster)->RemoveSpellCooldown(spellId);
1739 m_caster->CastSpell(m_caster, spellId, true);
1740 return;
1742 // just skip
1743 case 23770: // Sayge's Dark Fortune of *
1744 // not exist, common cooldown can be implemented in scripts if need.
1745 return;
1746 // Brittle Armor - (need add max stack of 24575 Brittle Armor)
1747 case 29284:
1749 const SpellEntry *spell = sSpellStore.LookupEntry(24575);
1750 if (!spell)
1751 return;
1753 for (int i=0; i < spell->StackAmount; ++i)
1754 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1755 return;
1757 // Mercurial Shield - (need add max stack of 26464 Mercurial Shield)
1758 case 29286:
1760 const SpellEntry *spell = sSpellStore.LookupEntry(26464);
1761 if (!spell)
1762 return;
1764 for (int i=0; i < spell->StackAmount; ++i)
1765 m_caster->CastSpell(unitTarget,spell->Id, true, m_CastItem, NULL, m_originalCasterGUID);
1766 return;
1768 // Righteous Defense
1769 case 31980:
1771 m_caster->CastSpell(unitTarget, 31790, true,m_CastItem,NULL,m_originalCasterGUID);
1772 return;
1774 // Cloak of Shadows
1775 case 35729 :
1777 Unit::AuraMap& Auras = m_caster->GetAuras();
1778 for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
1780 // remove all harmful spells on you...
1781 if( // ignore positive and passive auras
1782 !iter->second->IsPositive() && !iter->second->IsPassive() &&
1783 // ignore physical auras
1784 (GetSpellSchoolMask(iter->second->GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)==0 &&
1785 // ignore immunity persistent spells
1786 !( iter->second->GetSpellProto()->AttributesEx & 0x10000 ) )
1788 m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
1789 iter = Auras.begin();
1792 return;
1794 // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
1795 case 41967:
1797 if (Unit *pet = m_caster->GetPet())
1798 pet->CastSpell(pet, 28305, true);
1799 return;
1803 // normal case
1804 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1806 if(!spellInfo)
1808 sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
1809 return;
1812 // some triggered spells require specific equipment
1813 if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
1815 // main hand weapon required
1816 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
1818 Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
1820 // skip spell if no weapon in slot or broken
1821 if(!item || item->IsBroken() )
1822 return;
1824 // skip spell if weapon not fit to triggered spell
1825 if(!item->IsFitToSpellRequirements(spellInfo))
1826 return;
1829 // offhand hand weapon required
1830 if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
1832 Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
1834 // skip spell if no weapon in slot or broken
1835 if(!item || item->IsBroken() )
1836 return;
1838 // skip spell if weapon not fit to triggered spell
1839 if(!item->IsFitToSpellRequirements(spellInfo))
1840 return;
1844 // some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
1845 bool instant = false;
1846 for(uint32 j = i+1; j < 3; ++j)
1848 if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
1850 instant = true;
1851 break;
1855 if(instant)
1857 if (unitTarget)
1858 m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
1860 else
1861 m_TriggerSpells.push_back(spellInfo);
1864 void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
1866 uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effect_idx];
1868 // normal case
1869 SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
1871 if(!spellInfo)
1873 sLog.outError("EffectTriggerMissileSpell of spell %u: triggering unknown spell id %effect_idx", m_spellInfo->Id,triggered_spell_id);
1874 return;
1877 if (m_CastItem)
1878 DEBUG_LOG("WORLD: cast Item spellId - %i", spellInfo->Id);
1880 Spell *spell = new Spell(m_caster, spellInfo, true, m_originalCasterGUID );
1882 SpellCastTargets targets;
1883 targets.setDestination(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ);
1884 spell->m_CastItem = m_CastItem;
1885 spell->prepare(&targets, NULL);
1888 void Spell::EffectTeleportUnits(uint32 i)
1890 if(!unitTarget || unitTarget->isInFlight())
1891 return;
1893 switch (m_spellInfo->EffectImplicitTargetB[i])
1895 case TARGET_INNKEEPER_COORDINATES:
1897 // Only players can teleport to innkeeper
1898 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1899 return;
1901 ((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);
1902 return;
1904 case TARGET_TABLE_X_Y_Z_COORDINATES:
1906 // TODO: Only players can teleport?
1907 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
1908 return;
1909 SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id);
1910 if(!st)
1912 sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id );
1913 return;
1915 ((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);
1916 break;
1918 case TARGET_BEHIND_VICTIM:
1920 // Get selected target for player (or victim for units)
1921 Unit *pTarget = NULL;
1922 if(m_caster->GetTypeId() == TYPEID_PLAYER)
1923 pTarget = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
1924 else
1925 pTarget = m_caster->getVictim();
1926 // No target present - return
1927 if (!pTarget)
1928 return;
1929 // Init dest coordinates
1930 uint32 mapid = m_caster->GetMapId();
1931 float x = m_targets.m_destX;
1932 float y = m_targets.m_destY;
1933 float z = m_targets.m_destZ;
1934 float orientation = pTarget->GetOrientation();
1935 // Teleport
1936 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1937 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
1938 else
1940 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1941 WorldPacket data;
1942 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1943 unitTarget->SendMessageToSet(&data, false);
1945 return;
1947 default:
1949 // If not exist data for dest location - return
1950 if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
1952 sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id );
1953 return;
1955 // Init dest coordinates
1956 uint32 mapid = m_caster->GetMapId();
1957 float x = m_targets.m_destX;
1958 float y = m_targets.m_destY;
1959 float z = m_targets.m_destZ;
1960 float orientation = unitTarget->GetOrientation();
1961 // Teleport
1962 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
1963 ((Player*)unitTarget)->TeleportTo(mapid, x, y, z, orientation, TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
1964 else
1966 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)unitTarget, x, y, z, orientation);
1967 WorldPacket data;
1968 unitTarget->BuildTeleportAckMsg(&data, x, y, z, orientation);
1969 unitTarget->SendMessageToSet(&data, false);
1971 return;
1975 // post effects for TARGET_TABLE_X_Y_Z_COORDINATES
1976 switch ( m_spellInfo->Id )
1978 // Dimensional Ripper - Everlook
1979 case 23442:
1981 int32 r = irand(0, 119);
1982 if ( r >= 70 ) // 7/12 success
1984 if ( r < 100 ) // 4/12 evil twin
1985 m_caster->CastSpell(m_caster,23445,true);
1986 else // 1/12 fire
1987 m_caster->CastSpell(m_caster,23449,true);
1989 return;
1991 // Ultrasafe Transporter: Toshley's Station
1992 case 36941:
1994 if ( roll_chance_i(50) ) // 50% success
1996 int32 rand_eff = urand(1,7);
1997 switch ( rand_eff )
1999 case 1:
2000 // soul split - evil
2001 m_caster->CastSpell(m_caster,36900,true);
2002 break;
2003 case 2:
2004 // soul split - good
2005 m_caster->CastSpell(m_caster,36901,true);
2006 break;
2007 case 3:
2008 // Increase the size
2009 m_caster->CastSpell(m_caster,36895,true);
2010 break;
2011 case 4:
2012 // Decrease the size
2013 m_caster->CastSpell(m_caster,36893,true);
2014 break;
2015 case 5:
2016 // Transform
2018 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2019 m_caster->CastSpell(m_caster,36897,true);
2020 else
2021 m_caster->CastSpell(m_caster,36899,true);
2022 break;
2024 case 6:
2025 // chicken
2026 m_caster->CastSpell(m_caster,36940,true);
2027 break;
2028 case 7:
2029 // evil twin
2030 m_caster->CastSpell(m_caster,23445,true);
2031 break;
2034 return;
2036 // Dimensional Ripper - Area 52
2037 case 36890:
2039 if ( roll_chance_i(50) ) // 50% success
2041 int32 rand_eff = urand(1,4);
2042 switch ( rand_eff )
2044 case 1:
2045 // soul split - evil
2046 m_caster->CastSpell(m_caster,36900,true);
2047 break;
2048 case 2:
2049 // soul split - good
2050 m_caster->CastSpell(m_caster,36901,true);
2051 break;
2052 case 3:
2053 // Increase the size
2054 m_caster->CastSpell(m_caster,36895,true);
2055 break;
2056 case 4:
2057 // Transform
2059 if (((Player*)m_caster)->GetTeam() == ALLIANCE )
2060 m_caster->CastSpell(m_caster,36897,true);
2061 else
2062 m_caster->CastSpell(m_caster,36899,true);
2063 break;
2067 return;
2072 void Spell::EffectApplyAura(uint32 i)
2074 if(!unitTarget)
2075 return;
2077 SpellImmuneList const& list = unitTarget->m_spellImmune[IMMUNITY_STATE];
2078 for(SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
2079 if(itr->type == m_spellInfo->EffectApplyAuraName[i])
2080 return;
2082 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
2083 if( !unitTarget->isAlive() && m_spellInfo->Id != 20584 && m_spellInfo->Id != 8326 &&
2084 (unitTarget->GetTypeId()!=TYPEID_PLAYER || !((Player*)unitTarget)->GetSession()->PlayerLoading()) )
2085 return;
2087 Unit* caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2088 if(!caster)
2089 return;
2091 sLog.outDebug("Spell: Aura is: %u", m_spellInfo->EffectApplyAuraName[i]);
2093 Aura* Aur = CreateAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, caster, m_CastItem);
2095 // Now Reduce spell duration using data received at spell hit
2096 int32 duration = Aur->GetAuraMaxDuration();
2097 unitTarget->ApplyDiminishingToDuration(m_diminishGroup,duration,m_caster,m_diminishLevel);
2098 Aur->setDiminishGroup(m_diminishGroup);
2100 // if Aura removed and deleted, do not continue.
2101 if(duration== 0 && !(Aur->IsPermanent()))
2103 delete Aur;
2104 return;
2107 if(duration != Aur->GetAuraMaxDuration())
2109 Aur->SetAuraMaxDuration(duration);
2110 Aur->SetAuraDuration(duration);
2113 bool added = unitTarget->AddAura(Aur);
2115 // Aura not added and deleted in AddAura call;
2116 if (!added)
2117 return;
2119 // found crash at character loading, broken pointer to Aur...
2120 // Aur was deleted in AddAura()...
2121 if(!Aur)
2122 return;
2124 // TODO Make a way so it works for every related spell!
2125 if(unitTarget->GetTypeId()==TYPEID_PLAYER) // Negative buff should only be applied on players
2127 uint32 spellId = 0;
2128 if(m_spellInfo->CasterAuraStateNot==AURA_STATE_WEAKENED_SOUL || m_spellInfo->TargetAuraStateNot==AURA_STATE_WEAKENED_SOUL)
2129 spellId = 6788; // Weakened Soul
2130 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_FORBEARANCE || m_spellInfo->TargetAuraStateNot==AURA_STATE_FORBEARANCE)
2131 spellId = 25771; // Forbearance
2132 else if(m_spellInfo->CasterAuraStateNot==AURA_STATE_HYPOTHERMIA)
2133 spellId = 41425; // Hypothermia
2134 else if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
2135 spellId = 11196; // Recently Bandaged
2136 else if( (m_spellInfo->AttributesEx & 0x20) && (m_spellInfo->AttributesEx2 & 0x20000) )
2137 spellId = 23230; // Blood Fury - Healing Reduction
2139 SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
2140 if (AdditionalSpellInfo)
2142 // applied at target by target
2143 Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unitTarget,unitTarget, 0);
2144 unitTarget->AddAura(AdditionalAura);
2145 sLog.outDebug("Spell: Additional Aura is: %u", AdditionalSpellInfo->EffectApplyAuraName[0]);
2149 // Prayer of Mending (jump animation), we need formal caster instead original for correct animation
2150 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
2151 m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
2154 void Spell::EffectUnlearnSpecialization( uint32 i )
2156 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2157 return;
2159 Player *_player = (Player*)unitTarget;
2160 uint32 spellToUnlearn = m_spellInfo->EffectTriggerSpell[i];
2162 _player->removeSpell(spellToUnlearn);
2164 sLog.outDebug( "Spell: Player %u have unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow() );
2167 void Spell::EffectPowerDrain(uint32 i)
2169 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2170 return;
2172 Powers drain_power = Powers(m_spellInfo->EffectMiscValue[i]);
2174 if(!unitTarget)
2175 return;
2176 if(!unitTarget->isAlive())
2177 return;
2178 if(unitTarget->getPowerType() != drain_power)
2179 return;
2180 if(damage < 0)
2181 return;
2183 uint32 curPower = unitTarget->GetPower(drain_power);
2185 //add spell damage bonus
2186 damage=m_caster->SpellDamageBonus(unitTarget,m_spellInfo,uint32(damage),SPELL_DIRECT_DAMAGE);
2188 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2189 uint32 power = damage;
2190 if ( drain_power == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2191 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2193 int32 new_damage;
2194 if(curPower < power)
2195 new_damage = curPower;
2196 else
2197 new_damage = power;
2199 unitTarget->ModifyPower(drain_power,-new_damage);
2201 if(drain_power == POWER_MANA)
2203 float manaMultiplier = m_spellInfo->EffectMultipleValue[i];
2204 if(manaMultiplier==0)
2205 manaMultiplier = 1;
2207 if(Player *modOwner = m_caster->GetSpellModOwner())
2208 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, manaMultiplier);
2210 int32 gain = int32(new_damage*manaMultiplier);
2212 m_caster->ModifyPower(POWER_MANA,gain);
2213 //send log
2214 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id,gain,POWER_MANA,false);
2218 void Spell::EffectSendEvent(uint32 EffectIndex)
2220 if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->InBattleGround())
2222 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
2223 if(bg && bg->GetStatus() == STATUS_IN_PROGRESS)
2225 switch(m_spellInfo->Id)
2227 case 23333: // Pickup Horde Flag
2228 /*do not uncomment .
2229 if(bg->GetTypeID()==BATTLEGROUND_WS)
2230 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2231 sLog.outDebug("Send Event Horde Flag Picked Up");
2232 break;
2233 /* not used :
2234 case 23334: // Drop Horde Flag
2235 if(bg->GetTypeID()==BATTLEGROUND_WS)
2236 bg->EventPlayerDroppedFlag((Player*)m_caster);
2237 sLog.outDebug("Drop Horde Flag");
2238 break;
2240 case 23335: // Pickup Alliance Flag
2241 /*do not uncomment ... (it will cause crash, because of null targetobject!) anyway this is a bad way to call that event, because it would cause recursion
2242 if(bg->GetTypeID()==BATTLEGROUND_WS)
2243 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2244 sLog.outDebug("Send Event Alliance Flag Picked Up");
2245 break;
2246 /* not used :
2247 case 23336: // Drop Alliance Flag
2248 if(bg->GetTypeID()==BATTLEGROUND_WS)
2249 bg->EventPlayerDroppedFlag((Player*)m_caster);
2250 sLog.outDebug("Drop Alliance Flag");
2251 break;
2252 case 23385: // Alliance Flag Returns
2253 if(bg->GetTypeID()==BATTLEGROUND_WS)
2254 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2255 sLog.outDebug("Alliance Flag Returned");
2256 break;
2257 case 23386: // Horde Flag Returns
2258 if(bg->GetTypeID()==BATTLEGROUND_WS)
2259 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2260 sLog.outDebug("Horde Flag Returned");
2261 break;*/
2262 case 34976:
2264 if(bg->GetTypeID()==BATTLEGROUND_EY)
2265 bg->EventPlayerClickedOnFlag((Player*)m_caster, this->gameObjTarget);
2267 break;
2268 default:
2269 sLog.outDebug("Unknown spellid %u in BG event", m_spellInfo->Id);
2270 break;
2274 sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
2275 sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
2278 void Spell::EffectPowerBurn(uint32 i)
2280 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2281 return;
2283 Powers powertype = Powers(m_spellInfo->EffectMiscValue[i]);
2285 if(!unitTarget)
2286 return;
2287 if(!unitTarget->isAlive())
2288 return;
2289 if(unitTarget->getPowerType()!=powertype)
2290 return;
2291 if(damage < 0)
2292 return;
2294 int32 curPower = int32(unitTarget->GetPower(powertype));
2296 // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
2297 uint32 power = damage;
2298 if ( powertype == POWER_MANA && unitTarget->GetTypeId() == TYPEID_PLAYER )
2299 power -= ((Player*)unitTarget)->GetSpellCritDamageReduction(power);
2301 int32 new_damage = (curPower < power) ? curPower : power;
2303 unitTarget->ModifyPower(powertype,-new_damage);
2304 float multiplier = m_spellInfo->EffectMultipleValue[i];
2306 if(Player *modOwner = m_caster->GetSpellModOwner())
2307 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2309 new_damage = int32(new_damage*multiplier);
2310 m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2313 void Spell::EffectHeal( uint32 /*i*/ )
2315 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2317 // Try to get original caster
2318 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2320 // Skip if m_originalCaster not available
2321 if (!caster)
2322 return;
2324 int32 addhealth = damage;
2326 // Vessel of the Naaru (Vial of the Sunwell trinket)
2327 if (m_spellInfo->Id == 45064)
2329 // Amount of heal - depends from stacked Holy Energy
2330 int damageAmount = 0;
2331 Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
2332 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
2333 if((*i)->GetId() == 45062)
2334 damageAmount+=(*i)->GetModifier()->m_amount;
2335 if (damageAmount)
2336 m_caster->RemoveAurasDueToSpell(45062);
2338 addhealth += damageAmount;
2340 // Swiftmend - consumes Regrowth or Rejuvenation
2341 else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND))
2343 Unit::AuraList const& RejorRegr = unitTarget->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
2344 // find most short by duration
2345 Aura *targetAura = NULL;
2346 for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
2348 if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
2349 && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
2351 if(!targetAura || (*i)->GetAuraDuration() < targetAura->GetAuraDuration())
2352 targetAura = *i;
2356 if(!targetAura)
2358 sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
2359 return;
2361 int idx = 0;
2362 while(idx < 3)
2364 if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
2365 break;
2366 idx++;
2369 int32 tickheal = caster->SpellHealingBonus(targetAura->GetSpellProto(), targetAura->GetModifier()->m_amount, DOT, unitTarget);
2370 int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
2371 unitTarget->RemoveAurasDueToSpell(targetAura->GetId());
2373 addhealth += tickheal * tickcount;
2375 else
2376 addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
2378 bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
2379 if (crit)
2380 addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
2381 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
2383 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2384 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2386 if(caster->GetTypeId()==TYPEID_PLAYER)
2387 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2388 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2390 // ignore item heals
2391 if(m_CastItem)
2392 return;
2394 uint32 procHealer = PROC_FLAG_HEAL;
2395 if (crit)
2396 procHealer |= PROC_FLAG_CRIT_HEAL;
2398 m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
2402 void Spell::EffectHealPct( uint32 /*i*/ )
2404 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2406 // Try to get original caster
2407 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2409 // Skip if m_originalCaster not available
2410 if (!caster)
2411 return;
2413 uint32 addhealth = unitTarget->GetMaxHealth() * damage / 100;
2414 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2416 int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
2417 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
2419 if(caster->GetTypeId()==TYPEID_PLAYER)
2420 if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
2421 bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
2425 void Spell::EffectHealMechanical( uint32 /*i*/ )
2427 // Mechanic creature type should be correctly checked by targetCreatureType field
2428 if( unitTarget && unitTarget->isAlive() && damage >= 0)
2430 // Try to get original caster
2431 Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
2433 // Skip if m_originalCaster not available
2434 if (!caster)
2435 return;
2437 uint32 addhealth = caster->SpellHealingBonus(m_spellInfo, uint32(damage), HEAL, unitTarget);
2438 caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, false);
2439 unitTarget->ModifyHealth( int32(damage) );
2443 void Spell::EffectHealthLeech(uint32 i)
2445 if(!unitTarget)
2446 return;
2447 if(!unitTarget->isAlive())
2448 return;
2450 if(damage < 0)
2451 return;
2453 sLog.outDebug("HealthLeech :%i", damage);
2455 float multiplier = m_spellInfo->EffectMultipleValue[i];
2457 if(Player *modOwner = m_caster->GetSpellModOwner())
2458 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
2460 int32 new_damage = int32(damage*multiplier);
2461 uint32 curHealth = unitTarget->GetHealth();
2462 new_damage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
2463 if(curHealth < new_damage)
2464 new_damage = curHealth;
2466 if(m_caster->isAlive())
2468 new_damage = m_caster->SpellHealingBonus(m_spellInfo, new_damage, HEAL, m_caster);
2470 m_caster->ModifyHealth(new_damage);
2472 if(m_caster->GetTypeId() == TYPEID_PLAYER)
2473 m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
2477 void Spell::DoCreateItem(uint32 i, uint32 itemtype)
2479 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
2480 return;
2482 Player* player = (Player*)unitTarget;
2484 uint32 newitemid = itemtype;
2485 ItemPrototype const *pProto = objmgr.GetItemPrototype( newitemid );
2486 if(!pProto)
2488 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2489 return;
2492 uint32 num_to_add;
2494 // TODO: maybe all this can be replaced by using correct calculated `damage` value
2495 if(pProto->Class != ITEM_CLASS_CONSUMABLE || m_spellInfo->SpellFamilyName != SPELLFAMILY_MAGE)
2497 int32 basePoints = m_currentBasePoints[i];
2498 int32 randomPoints = m_spellInfo->EffectDieSides[i];
2499 if (randomPoints)
2500 num_to_add = basePoints + irand(1, randomPoints);
2501 else
2502 num_to_add = basePoints + 1;
2504 else if (pProto->MaxCount == 1)
2505 num_to_add = 1;
2506 else if(player->getLevel() >= m_spellInfo->spellLevel)
2508 int32 basePoints = m_currentBasePoints[i];
2509 float pointPerLevel = m_spellInfo->EffectRealPointsPerLevel[i];
2510 num_to_add = basePoints + 1 + uint32((player->getLevel() - m_spellInfo->spellLevel)*pointPerLevel);
2512 else
2513 num_to_add = 2;
2515 if (num_to_add < 1)
2516 num_to_add = 1;
2517 if (num_to_add > pProto->Stackable)
2518 num_to_add = pProto->Stackable;
2520 // init items_count to 1, since 1 item will be created regardless of specialization
2521 int items_count=1;
2522 // the chance to create additional items
2523 float additionalCreateChance=0.0f;
2524 // the maximum number of created additional items
2525 uint8 additionalMaxNum=0;
2526 // get the chance and maximum number for creating extra items
2527 if ( canCreateExtraItems(player, m_spellInfo->Id, additionalCreateChance, additionalMaxNum) )
2529 // roll with this chance till we roll not to create or we create the max num
2530 while ( roll_chance_f(additionalCreateChance) && items_count<=additionalMaxNum )
2531 ++items_count;
2534 // really will be created more items
2535 num_to_add *= items_count;
2537 // can the player store the new item?
2538 ItemPosCountVec dest;
2539 uint32 no_space = 0;
2540 uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, num_to_add, &no_space );
2541 if( msg != EQUIP_ERR_OK )
2543 // convert to possible store amount
2544 if( msg == EQUIP_ERR_INVENTORY_FULL || msg == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS )
2545 num_to_add -= no_space;
2546 else
2548 // if not created by another reason from full inventory or unique items amount limitation
2549 player->SendEquipError( msg, NULL, NULL );
2550 return;
2554 if(num_to_add)
2556 // create the new item and store it
2557 Item* pItem = player->StoreNewItem( dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
2559 // was it successful? return error if not
2560 if(!pItem)
2562 player->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
2563 return;
2566 // set the "Crafted by ..." property of the item
2567 if( pItem->GetProto()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetProto()->Class != ITEM_CLASS_QUEST)
2568 pItem->SetUInt32Value(ITEM_FIELD_CREATOR,player->GetGUIDLow());
2570 // send info to the client
2571 if(pItem)
2572 player->SendNewItem(pItem, num_to_add, true, true);
2574 // we succeeded in creating at least one item, so a levelup is possible
2575 player->UpdateCraftSkill(m_spellInfo->Id);
2578 // for battleground marks send by mail if not add all expected
2579 if(no_space > 0 )
2581 BattleGroundTypeId bgType;
2582 switch(m_spellInfo->Id)
2584 case SPELL_AV_MARK_WINNER:
2585 case SPELL_AV_MARK_LOSER:
2586 bgType = BATTLEGROUND_AV;
2587 break;
2588 case SPELL_WS_MARK_WINNER:
2589 case SPELL_WS_MARK_LOSER:
2590 bgType = BATTLEGROUND_WS;
2591 break;
2592 case SPELL_AB_MARK_WINNER:
2593 case SPELL_AB_MARK_LOSER:
2594 bgType = BATTLEGROUND_AB;
2595 break;
2596 default:
2597 return;
2600 if(BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgType))
2601 bg->SendRewardMarkByMail(player,newitemid,no_space);
2605 void Spell::EffectCreateItem(uint32 i)
2607 DoCreateItem(i,m_spellInfo->EffectItemType[i]);
2610 void Spell::EffectPersistentAA(uint32 i)
2612 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
2614 if(Player* modOwner = m_caster->GetSpellModOwner())
2615 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RADIUS, radius);
2617 int32 duration = GetSpellDuration(m_spellInfo);
2618 DynamicObject* dynObj = new DynamicObject;
2619 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))
2621 delete dynObj;
2622 return;
2624 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
2625 dynObj->SetUInt32Value(GAMEOBJECT_DISPLAYID, 368003);
2626 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x01eeeeee);
2627 m_caster->AddDynObject(dynObj);
2628 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
2631 void Spell::EffectEnergize(uint32 i)
2633 if(!unitTarget)
2634 return;
2635 if(!unitTarget->isAlive())
2636 return;
2638 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2639 return;
2641 // Some level depends spells
2642 int multipler = 0;
2643 int level_diff = 0;
2644 switch (m_spellInfo->Id)
2646 // Restore Energy
2647 case 9512:
2648 level_diff = m_caster->getLevel() - 40;
2649 multipler = 2;
2650 break;
2651 // Blood Fury
2652 case 24571:
2653 level_diff = m_caster->getLevel() - 60;
2654 multipler = 10;
2655 break;
2656 // Burst of Energy
2657 case 24532:
2658 level_diff = m_caster->getLevel() - 60;
2659 multipler = 4;
2660 break;
2661 default:
2662 break;
2665 if (level_diff > 0)
2666 damage -= multipler * level_diff;
2668 if(damage < 0)
2669 return;
2671 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2673 if(unitTarget->GetMaxPower(power) == 0)
2674 return;
2676 unitTarget->ModifyPower(power,damage);
2677 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2679 // Mad Alchemist's Potion
2680 if (m_spellInfo->Id == 45051)
2682 // find elixirs on target
2683 uint32 elixir_mask = 0;
2684 Unit::AuraMap& Auras = unitTarget->GetAuras();
2685 for(Unit::AuraMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
2687 uint32 spell_id = itr->second->GetId();
2688 if(uint32 mask = spellmgr.GetSpellElixirMask(spell_id))
2689 elixir_mask |= mask;
2692 // get available elixir mask any not active type from battle/guardian (and flask if no any)
2693 elixir_mask = (elixir_mask & ELIXIR_FLASK_MASK) ^ ELIXIR_FLASK_MASK;
2695 // get all available elixirs by mask and spell level
2696 std::vector<uint32> elixirs;
2697 SpellElixirMap const& m_spellElixirs = spellmgr.GetSpellElixirMap();
2698 for(SpellElixirMap::const_iterator itr = m_spellElixirs.begin(); itr != m_spellElixirs.end(); ++itr)
2700 if (itr->second & elixir_mask)
2702 if (itr->second & (ELIXIR_UNSTABLE_MASK | ELIXIR_SHATTRATH_MASK))
2703 continue;
2705 SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
2706 if (spellInfo && (spellInfo->spellLevel < m_spellInfo->spellLevel || spellInfo->spellLevel > unitTarget->getLevel()))
2707 continue;
2709 elixirs.push_back(itr->first);
2713 if (!elixirs.empty())
2715 // cast random elixir on target
2716 uint32 rand_spell = urand(0,elixirs.size()-1);
2717 m_caster->CastSpell(unitTarget,elixirs[rand_spell],true,m_CastItem);
2722 void Spell::EffectEnergisePct(uint32 i)
2724 if(!unitTarget)
2725 return;
2726 if(!unitTarget->isAlive())
2727 return;
2729 if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS)
2730 return;
2732 Powers power = Powers(m_spellInfo->EffectMiscValue[i]);
2734 uint32 maxPower = unitTarget->GetMaxPower(power);
2735 if(maxPower == 0)
2736 return;
2738 uint32 gain = damage * maxPower / 100;
2739 unitTarget->ModifyPower(power, gain);
2740 m_caster->SendEnergizeSpellLog(unitTarget, m_spellInfo->Id, damage, power);
2743 void Spell::SendLoot(uint64 guid, LootType loottype)
2745 Player* player = (Player*)m_caster;
2746 if (!player)
2747 return;
2749 if (gameObjTarget)
2751 switch (gameObjTarget->GetGoType())
2753 case GAMEOBJECT_TYPE_DOOR:
2754 case GAMEOBJECT_TYPE_BUTTON:
2755 gameObjTarget->UseDoorOrButton();
2756 sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
2757 return;
2759 case GAMEOBJECT_TYPE_QUESTGIVER:
2760 // start or end quest
2761 player->PrepareQuestMenu(guid);
2762 player->SendPreparedQuest(guid);
2763 return;
2765 case GAMEOBJECT_TYPE_SPELL_FOCUS:
2766 // triggering linked GO
2767 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->spellFocus.linkedTrapId)
2768 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2769 return;
2771 case GAMEOBJECT_TYPE_GOOBER:
2772 // goober_scripts can be triggered if the player don't have the quest
2773 if (gameObjTarget->GetGOInfo()->goober.eventId)
2775 sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
2776 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
2779 // cast goober spell
2780 if (gameObjTarget->GetGOInfo()->goober.questId)
2781 ///Quest require to be active for GO using
2782 if(player->GetQuestStatus(gameObjTarget->GetGOInfo()->goober.questId) != QUEST_STATUS_INCOMPLETE)
2783 return;
2785 gameObjTarget->AddUniqueUse(player);
2786 gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
2788 //TODO? Objective counting called without spell check but with quest objective check
2789 // if send spell id then this line will duplicate to spell casting call (double counting)
2790 // So we or have this line and not required in quest_template have reqSpellIdN
2791 // or must remove this line and required in DB have data in quest_template have reqSpellIdN for all quest using cases.
2792 player->CastedCreatureOrGO(gameObjTarget->GetEntry(), gameObjTarget->GetGUID(), 0);
2794 // triggering linked GO
2795 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
2796 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2798 return;
2800 case GAMEOBJECT_TYPE_CHEST:
2801 // TODO: possible must be moved to loot release (in different from linked triggering)
2802 if (gameObjTarget->GetGOInfo()->chest.eventId)
2804 sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
2805 sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
2808 // triggering linked GO
2809 if(uint32 trapEntry = gameObjTarget->GetGOInfo()->chest.linkedTrapId)
2810 gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
2812 // Don't return, let loots been taken
2816 // Send loot
2817 player->SendLoot(guid, loottype);
2820 void Spell::EffectOpenLock(uint32 /*i*/)
2822 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
2824 sLog.outDebug( "WORLD: Open Lock - No Player Caster!");
2825 return;
2828 Player* player = (Player*)m_caster;
2830 LootType loottype = LOOT_CORPSE;
2831 uint32 lockId = 0;
2832 uint64 guid = 0;
2834 // Get lockId
2835 if(gameObjTarget)
2837 GameObjectInfo const* goInfo = gameObjTarget->GetGOInfo();
2838 // Arathi Basin banner opening !
2839 if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune ||
2840 goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK )
2842 //isAllowUseBattleGroundObject() already called in CanCast()
2843 // in battleground check
2844 if(BattleGround *bg = player->GetBattleGround())
2846 // check if it's correct bg
2847 if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
2848 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2849 return;
2852 else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
2854 //isAllowUseBattleGroundObject() already called in CanCast()
2855 // in battleground check
2856 if(BattleGround *bg = player->GetBattleGround())
2858 if(bg->GetTypeID() == BATTLEGROUND_EY)
2859 bg->EventPlayerClickedOnFlag(player, gameObjTarget);
2860 return;
2863 lockId = gameObjTarget->GetLockId();
2864 guid = gameObjTarget->GetGUID();
2866 else if(itemTarget)
2868 lockId = itemTarget->GetProto()->LockID;
2869 guid = itemTarget->GetGUID();
2871 else
2873 sLog.outDebug( "WORLD: Open Lock - No GameObject/Item Target!");
2874 return;
2877 if(!lockId) // possible case for GO and maybe for items.
2879 SendLoot(guid, loottype);
2880 return;
2883 // Get LockInfo
2884 LockEntry const *lockInfo = sLockStore.LookupEntry(lockId);
2886 if (!lockInfo)
2888 sLog.outError( "Spell::EffectOpenLock: %s [guid = %u] has an unknown lockId: %u!",
2889 (gameObjTarget ? "gameobject" : "item"), GUID_LOPART(guid), lockId);
2890 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2891 return;
2894 // check key
2895 for(int i = 0; i < 5; ++i)
2897 // type==1 This means lockInfo->key[i] is an item
2898 if(lockInfo->keytype[i]==LOCK_KEY_ITEM && lockInfo->key[i] && m_CastItem && m_CastItem->GetEntry()==lockInfo->key[i])
2900 SendLoot(guid, loottype);
2901 return;
2905 uint32 SkillId = 0;
2906 // Check and skill-up skill
2907 if( m_spellInfo->Effect[1] == SPELL_EFFECT_SKILL )
2908 SkillId = m_spellInfo->EffectMiscValue[1];
2909 // pickpocketing spells
2910 else if( m_spellInfo->EffectMiscValue[0] == LOCKTYPE_PICKLOCK )
2911 SkillId = SKILL_LOCKPICKING;
2913 // skill bonus provided by casting spell (mostly item spells)
2914 uint32 spellSkillBonus = uint32(m_currentBasePoints[0]+1);
2916 uint32 reqSkillValue = lockInfo->requiredminingskill;
2918 if(lockInfo->requiredlockskill) // required pick lock skill applying
2920 if(SkillId != SKILL_LOCKPICKING) // wrong skill (cheating?)
2922 SendCastResult(SPELL_FAILED_FIZZLE);
2923 return;
2926 reqSkillValue = lockInfo->requiredlockskill;
2928 else if(SkillId == SKILL_LOCKPICKING) // apply picklock skill to wrong target
2930 SendCastResult(SPELL_FAILED_BAD_TARGETS);
2931 return;
2934 if ( SkillId )
2936 loottype = LOOT_SKINNING;
2937 if ( player->GetSkillValue(SkillId) + spellSkillBonus < reqSkillValue )
2939 SendCastResult(SPELL_FAILED_LOW_CASTLEVEL);
2940 return;
2943 // update skill if really known
2944 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2945 if(SkillValue) // non only item base skill
2947 if(gameObjTarget)
2949 // Allow one skill-up until respawned
2950 if ( !gameObjTarget->IsInSkillupList( player->GetGUIDLow() ) &&
2951 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue) )
2952 gameObjTarget->AddToSkillupList( player->GetGUIDLow() );
2954 else if(itemTarget)
2956 // Do one skill-up
2957 uint32 SkillValue = player->GetPureSkillValue(SkillId);
2958 player->UpdateGatherSkill(SkillId, SkillValue, reqSkillValue);
2963 SendLoot(guid, loottype);
2966 void Spell::EffectSummonChangeItem(uint32 i)
2968 if(m_caster->GetTypeId() != TYPEID_PLAYER)
2969 return;
2971 Player *player = (Player*)m_caster;
2973 // applied only to using item
2974 if(!m_CastItem)
2975 return;
2977 // ... only to item in own inventory/bank/equip_slot
2978 if(m_CastItem->GetOwnerGUID()!=player->GetGUID())
2979 return;
2981 uint32 newitemid = m_spellInfo->EffectItemType[i];
2982 if(!newitemid)
2983 return;
2985 uint16 pos = m_CastItem->GetPos();
2987 Item *pNewItem = Item::CreateItem( newitemid, 1, player);
2988 if( !pNewItem )
2989 return;
2991 for(uint8 i= PERM_ENCHANTMENT_SLOT; i<=TEMP_ENCHANTMENT_SLOT; ++i)
2993 if(m_CastItem->GetEnchantmentId(EnchantmentSlot(i)))
2994 pNewItem->SetEnchantment(EnchantmentSlot(i), m_CastItem->GetEnchantmentId(EnchantmentSlot(i)), m_CastItem->GetEnchantmentDuration(EnchantmentSlot(i)), m_CastItem->GetEnchantmentCharges(EnchantmentSlot(i)));
2997 if(m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) < m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY))
2999 double loosePercent = 1 - m_CastItem->GetUInt32Value(ITEM_FIELD_DURABILITY) / double(m_CastItem->GetUInt32Value(ITEM_FIELD_MAXDURABILITY));
3000 player->DurabilityLoss(pNewItem, loosePercent);
3003 if( player->IsInventoryPos( pos ) )
3005 ItemPosCountVec dest;
3006 uint8 msg = player->CanStoreItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3007 if( msg == EQUIP_ERR_OK )
3009 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3011 // prevent crash at access and unexpected charges counting with item update queue corrupt
3012 if(m_CastItem==m_targets.getItemTarget())
3013 m_targets.setItemTarget(NULL);
3015 m_CastItem = NULL;
3017 player->StoreItem( dest, pNewItem, true);
3018 return;
3021 else if( player->IsBankPos ( pos ) )
3023 ItemPosCountVec dest;
3024 uint8 msg = player->CanBankItem( m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), dest, pNewItem, true );
3025 if( msg == EQUIP_ERR_OK )
3027 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3029 // prevent crash at access and unexpected charges counting with item update queue corrupt
3030 if(m_CastItem==m_targets.getItemTarget())
3031 m_targets.setItemTarget(NULL);
3033 m_CastItem = NULL;
3035 player->BankItem( dest, pNewItem, true);
3036 return;
3039 else if( player->IsEquipmentPos ( pos ) )
3041 uint16 dest;
3042 uint8 msg = player->CanEquipItem( m_CastItem->GetSlot(), dest, pNewItem, true );
3043 if( msg == EQUIP_ERR_OK )
3045 player->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(),true);
3047 // prevent crash at access and unexpected charges counting with item update queue corrupt
3048 if(m_CastItem==m_targets.getItemTarget())
3049 m_targets.setItemTarget(NULL);
3051 m_CastItem = NULL;
3053 player->EquipItem( dest, pNewItem, true);
3054 player->AutoUnequipOffhandIfNeed();
3055 return;
3059 // fail
3060 delete pNewItem;
3063 void Spell::EffectOpenSecretSafe(uint32 i)
3065 EffectOpenLock(i); //no difference for now
3068 void Spell::EffectProficiency(uint32 /*i*/)
3070 if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
3071 return;
3072 Player *p_target = (Player*)unitTarget;
3074 uint32 subClassMask = m_spellInfo->EquippedItemSubClassMask;
3075 if(m_spellInfo->EquippedItemClass == 2 && !(p_target->GetWeaponProficiency() & subClassMask))
3077 p_target->AddWeaponProficiency(subClassMask);
3078 p_target->SendProficiency(uint8(0x02),p_target->GetWeaponProficiency());
3080 if(m_spellInfo->EquippedItemClass == 4 && !(p_target->GetArmorProficiency() & subClassMask))
3082 p_target->AddArmorProficiency(subClassMask);
3083 p_target->SendProficiency(uint8(0x04),p_target->GetArmorProficiency());
3087 void Spell::EffectApplyAreaAura(uint32 i)
3089 if(!unitTarget)
3090 return;
3091 if(!unitTarget->isAlive())
3092 return;
3094 AreaAura* Aur = new AreaAura(m_spellInfo, i, &m_currentBasePoints[i], unitTarget, m_caster, m_CastItem);
3095 unitTarget->AddAura(Aur);
3098 void Spell::EffectSummonType(uint32 i)
3100 switch(m_spellInfo->EffectMiscValueB[i])
3102 case SUMMON_TYPE_GUARDIAN:
3103 case SUMMON_TYPE_POSESSED:
3104 case SUMMON_TYPE_POSESSED2:
3105 EffectSummonGuardian(i);
3106 break;
3107 case SUMMON_TYPE_WILD:
3108 EffectSummonWild(i);
3109 break;
3110 case SUMMON_TYPE_DEMON:
3111 EffectSummonDemon(i);
3112 break;
3113 case SUMMON_TYPE_SUMMON:
3114 EffectSummon(i);
3115 break;
3116 case SUMMON_TYPE_CRITTER:
3117 case SUMMON_TYPE_CRITTER2:
3118 case SUMMON_TYPE_CRITTER3:
3119 EffectSummonCritter(i);
3120 break;
3121 case SUMMON_TYPE_TOTEM_SLOT1:
3122 case SUMMON_TYPE_TOTEM_SLOT2:
3123 case SUMMON_TYPE_TOTEM_SLOT3:
3124 case SUMMON_TYPE_TOTEM_SLOT4:
3125 case SUMMON_TYPE_TOTEM:
3126 EffectSummonTotem(i);
3127 break;
3128 case SUMMON_TYPE_UNKNOWN1:
3129 case SUMMON_TYPE_UNKNOWN2:
3130 case SUMMON_TYPE_UNKNOWN3:
3131 case SUMMON_TYPE_UNKNOWN4:
3132 case SUMMON_TYPE_UNKNOWN5:
3133 break;
3134 default:
3135 sLog.outError("EffectSummonType: Unhandled summon type %u", m_spellInfo->EffectMiscValueB[i]);
3136 break;
3140 void Spell::EffectSummon(uint32 i)
3142 if(m_caster->GetPetGUID())
3143 return;
3145 if(!unitTarget)
3146 return;
3147 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3148 if(!pet_entry)
3149 return;
3150 uint32 level = m_caster->getLevel();
3151 Pet* spawnCreature = new Pet(SUMMON_PET);
3153 if(spawnCreature->LoadPetFromDB(m_caster,pet_entry))
3155 // set timer for unsummon
3156 int32 duration = GetSpellDuration(m_spellInfo);
3157 if(duration > 0)
3158 spawnCreature->SetDuration(duration);
3160 return;
3163 Map *map = m_caster->GetMap();
3164 uint32 pet_number = objmgr.GeneratePetNumber();
3165 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),map,m_spellInfo->EffectMiscValue[i], pet_number))
3167 sLog.outErrorDb("Spell::EffectSummon: no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3168 delete spawnCreature;
3169 return;
3172 // Summon in dest location
3173 float x,y,z;
3174 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3176 x = m_targets.m_destX;
3177 y = m_targets.m_destY;
3178 z = m_targets.m_destZ;
3180 else
3181 m_caster->GetClosePoint(x,y,z,spawnCreature->GetObjectSize());
3183 spawnCreature->Relocate(x,y,z,-m_caster->GetOrientation());
3185 if(!spawnCreature->IsPositionValid())
3187 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3188 delete spawnCreature;
3189 return;
3192 // set timer for unsummon
3193 int32 duration = GetSpellDuration(m_spellInfo);
3194 if(duration > 0)
3195 spawnCreature->SetDuration(duration);
3197 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
3198 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3199 spawnCreature->setPowerType(POWER_MANA);
3200 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3201 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3202 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
3203 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3204 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3205 spawnCreature->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
3206 spawnCreature->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
3207 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3208 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3210 spawnCreature->InitStatsForLevel(level);
3212 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3214 spawnCreature->AIM_Initialize();
3215 spawnCreature->InitPetCreateSpells();
3216 spawnCreature->SetHealth(spawnCreature->GetMaxHealth());
3217 spawnCreature->SetPower(POWER_MANA, spawnCreature->GetMaxPower(POWER_MANA));
3219 std::string name = m_caster->GetName();
3220 name.append(petTypeSuffix[spawnCreature->getPetType()]);
3221 spawnCreature->SetName( name );
3223 map->Add((Creature*)spawnCreature);
3225 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3227 m_caster->SetPet(spawnCreature);
3228 spawnCreature->GetCharmInfo()->SetReactState( REACT_DEFENSIVE );
3229 spawnCreature->SavePetToDB(PET_SAVE_AS_CURRENT);
3230 ((Player*)m_caster)->PetSpellInitialize();
3234 void Spell::EffectLearnSpell(uint32 i)
3236 if(!unitTarget)
3237 return;
3239 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3241 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3242 EffectLearnPetSpell(i);
3244 return;
3247 Player *player = (Player*)unitTarget;
3249 uint32 spellToLearn = (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) ? damage : m_spellInfo->EffectTriggerSpell[i];
3250 player->learnSpell(spellToLearn);
3252 sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
3255 void Spell::EffectDispel(uint32 i)
3257 if(!unitTarget)
3258 return;
3260 // Fill possible dispell list
3261 std::vector <Aura *> dispel_list;
3263 // Create dispel mask by dispel type
3264 uint32 dispel_type = m_spellInfo->EffectMiscValue[i];
3265 uint32 dispelMask = GetDispellMask( DispelType(dispel_type) );
3266 Unit::AuraMap const& auras = unitTarget->GetAuras();
3267 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
3269 Aura *aur = (*itr).second;
3270 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
3272 if(aur->GetSpellProto()->Dispel == DISPEL_MAGIC)
3274 bool positive = true;
3275 if (!aur->IsPositive())
3276 positive = false;
3277 else
3278 positive = (aur->GetSpellProto()->AttributesEx & SPELL_ATTR_EX_NEGATIVE)==0;
3280 // do not remove positive auras if friendly target
3281 // negative auras if non-friendly target
3282 if(positive == unitTarget->IsFriendlyTo(m_caster))
3283 continue;
3285 // Add aura to dispel list
3286 dispel_list.push_back(aur);
3289 // Ok if exist some buffs for dispel try dispel it
3290 if (!dispel_list.empty())
3292 std::list < std::pair<uint32,uint64> > success_list;// (spell_id,casterGuid)
3293 std::list < uint32 > fail_list; // spell_id
3294 int32 list_size = dispel_list.size();
3295 // Dispell N = damage buffs (or while exist buffs for dispel)
3296 for (int32 count=0; count < damage && list_size > 0; ++count)
3298 // Random select buff for dispel
3299 Aura *aur = dispel_list[urand(0, list_size-1)];
3301 SpellEntry const* spellInfo = aur->GetSpellProto();
3302 // Base dispel chance
3303 // TODO: possible chance depend from spell level??
3304 int32 miss_chance = 0;
3305 // Apply dispel mod from aura caster
3306 if (Unit *caster = aur->GetCaster())
3308 if ( Player* modOwner = caster->GetSpellModOwner() )
3309 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_RESIST_DISPEL_CHANCE, miss_chance, this);
3311 // Try dispel
3312 if (roll_chance_i(miss_chance))
3313 fail_list.push_back(aur->GetId());
3314 else
3315 success_list.push_back(std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
3316 // Remove buff from list for prevent doubles
3317 for (std::vector<Aura *>::iterator j = dispel_list.begin(); j != dispel_list.end(); )
3319 Aura *dispeled = *j;
3320 if (dispeled->GetId() == aur->GetId() && dispeled->GetCasterGUID() == aur->GetCasterGUID())
3322 j = dispel_list.erase(j);
3323 --list_size;
3325 else
3326 ++j;
3329 // Send success log and really remove auras
3330 if (!success_list.empty())
3332 int32 count = success_list.size();
3333 WorldPacket data(SMSG_SPELLDISPELLOG, 8+8+4+1+4+count*5);
3334 data.append(unitTarget->GetPackGUID()); // Victim GUID
3335 data.append(m_caster->GetPackGUID()); // Caster GUID
3336 data << uint32(m_spellInfo->Id); // Dispell spell id
3337 data << uint8(0); // not used
3338 data << uint32(count); // count
3339 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
3341 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
3342 data << uint32(spellInfo->Id); // Spell Id
3343 data << uint8(0); // 0 - dispeled !=0 cleansed
3344 unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
3346 m_caster->SendMessageToSet(&data, true);
3348 // On succes dispel
3349 // Devour Magic
3350 if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
3352 uint32 heal_spell = 0;
3353 switch (m_spellInfo->Id)
3355 case 19505: heal_spell = 19658; break;
3356 case 19731: heal_spell = 19732; break;
3357 case 19734: heal_spell = 19733; break;
3358 case 19736: heal_spell = 19735; break;
3359 case 27276: heal_spell = 27278; break;
3360 case 27277: heal_spell = 27279; break;
3361 default:
3362 sLog.outDebug("Spell for Devour Magic %d not handled in Spell::EffectDispel", m_spellInfo->Id);
3363 break;
3365 if (heal_spell)
3366 m_caster->CastSpell(m_caster, heal_spell, true);
3369 // Send fail log to client
3370 if (!fail_list.empty())
3372 // Failed to dispell
3373 WorldPacket data(SMSG_DISPEL_FAILED, 8+8+4+4*fail_list.size());
3374 data << uint64(m_caster->GetGUID()); // Caster GUID
3375 data << uint64(unitTarget->GetGUID()); // Victim GUID
3376 data << uint32(m_spellInfo->Id); // Dispell spell id
3377 for (std::list< uint32 >::iterator j = fail_list.begin(); j != fail_list.end(); ++j)
3378 data << uint32(*j); // Spell Id
3379 m_caster->SendMessageToSet(&data, true);
3384 void Spell::EffectDualWield(uint32 /*i*/)
3386 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
3387 ((Player*)unitTarget)->SetCanDualWield(true);
3390 void Spell::EffectPull(uint32 /*i*/)
3392 // TODO: create a proper pull towards distract spell center for distract
3393 sLog.outDebug("WORLD: Spell Effect DUMMY");
3396 void Spell::EffectDistract(uint32 /*i*/)
3398 // Check for possible target
3399 if (!unitTarget || unitTarget->isInCombat())
3400 return;
3402 // target must be OK to do this
3403 if( unitTarget->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING ) )
3404 return;
3406 float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY);
3408 if ( unitTarget->GetTypeId() == TYPEID_PLAYER )
3410 // For players just turn them
3411 WorldPacket data;
3412 ((Player*)unitTarget)->BuildTeleportAckMsg(&data, unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle);
3413 ((Player*)unitTarget)->GetSession()->SendPacket( &data );
3414 ((Player*)unitTarget)->SetPosition(unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), angle, false);
3416 else
3418 // Set creature Distracted, Stop it, And turn it
3419 unitTarget->SetOrientation(angle);
3420 unitTarget->StopMoving();
3421 unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
3425 void Spell::EffectPickPocket(uint32 /*i*/)
3427 if( m_caster->GetTypeId() != TYPEID_PLAYER )
3428 return;
3430 // victim must be creature and attackable
3431 if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) )
3432 return;
3434 // victim have to be alive and humanoid or undead
3435 if( unitTarget->isAlive() && (unitTarget->GetCreatureTypeMask() &CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD) != 0)
3437 int32 chance = 10 + int32(m_caster->getLevel()) - int32(unitTarget->getLevel());
3439 if (chance > irand(0, 19))
3441 // Stealing successful
3442 //sLog.outDebug("Sending loot from pickpocket");
3443 ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING);
3445 else
3447 // Reveal action + get attack
3448 m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
3449 if (((Creature*)unitTarget)->AI())
3450 ((Creature*)unitTarget)->AI()->AttackStart(m_caster);
3455 void Spell::EffectAddFarsight(uint32 i)
3457 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3458 int32 duration = GetSpellDuration(m_spellInfo);
3459 DynamicObject* dynObj = new DynamicObject;
3460 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))
3462 delete dynObj;
3463 return;
3465 dynObj->SetUInt32Value(OBJECT_FIELD_TYPE, 65);
3466 dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
3467 m_caster->AddDynObject(dynObj);
3468 MapManager::Instance().GetMap(dynObj->GetMapId(), dynObj)->Add(dynObj);
3469 m_caster->SetUInt64Value(PLAYER_FARSIGHT, dynObj->GetGUID());
3472 void Spell::EffectSummonWild(uint32 i)
3474 uint32 creature_entry = m_spellInfo->EffectMiscValue[i];
3475 if(!creature_entry)
3476 return;
3478 uint32 level = m_caster->getLevel();
3480 // level of creature summoned using engineering item based at engineering skill level
3481 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3483 ItemPrototype const *proto = m_CastItem->GetProto();
3484 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3486 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3487 if(skill202)
3489 level = skill202/5;
3494 // select center of summon position
3495 float center_x = m_targets.m_destX;
3496 float center_y = m_targets.m_destY;
3497 float center_z = m_targets.m_destZ;
3499 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3501 int32 amount = damage > 0 ? damage : 1;
3503 for(int32 count = 0; count < amount; ++count)
3505 float px, py, pz;
3506 // If dest location if present
3507 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3509 // Summon 1 unit in dest location
3510 if (count == 0)
3512 px = m_targets.m_destX;
3513 py = m_targets.m_destY;
3514 pz = m_targets.m_destZ;
3516 // Summon in random point all other units if location present
3517 else
3518 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3520 // Summon if dest location not present near caster
3521 else
3522 m_caster->GetClosePoint(px,py,pz,3.0f);
3524 int32 duration = GetSpellDuration(m_spellInfo);
3526 TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
3528 m_caster->SummonCreature(creature_entry,px,py,pz,m_caster->GetOrientation(),summonType,duration);
3532 void Spell::EffectSummonGuardian(uint32 i)
3534 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
3535 if(!pet_entry)
3536 return;
3538 // Jewelery statue case (totem like)
3539 if(m_spellInfo->SpellIconID==2056)
3541 EffectSummonTotem(i);
3542 return;
3545 // set timer for unsummon
3546 int32 duration = GetSpellDuration(m_spellInfo);
3548 // Search old Guardian only for players (if casted spell not have duration or cooldown)
3549 // FIXME: some guardians have control spell applied and controlled by player and anyway player can't summon in this time
3550 // so this code hack in fact
3551 if( m_caster->GetTypeId() == TYPEID_PLAYER && (duration <= 0 || GetSpellRecoveryTime(m_spellInfo)==0) )
3552 if(((Player*)m_caster)->HasGuardianWithEntry(pet_entry))
3553 return; // find old guardian, ignore summon
3555 // in another case summon new
3556 uint32 level = m_caster->getLevel();
3558 // level of pet summoned using engineering item based at engineering skill level
3559 if(m_caster->GetTypeId()==TYPEID_PLAYER && m_CastItem)
3561 ItemPrototype const *proto = m_CastItem->GetProto();
3562 if(proto && proto->RequiredSkill == SKILL_ENGINERING)
3564 uint16 skill202 = ((Player*)m_caster)->GetSkillValue(SKILL_ENGINERING);
3565 if(skill202)
3567 level = skill202/5;
3572 // select center of summon position
3573 float center_x = m_targets.m_destX;
3574 float center_y = m_targets.m_destY;
3575 float center_z = m_targets.m_destZ;
3577 float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3579 int32 amount = damage > 0 ? damage : 1;
3581 for(int32 count = 0; count < amount; ++count)
3583 Pet* spawnCreature = new Pet(GUARDIAN_PET);
3585 Map *map = m_caster->GetMap();
3586 uint32 pet_number = objmgr.GeneratePetNumber();
3587 if(!spawnCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map,m_spellInfo->EffectMiscValue[i], pet_number))
3589 sLog.outError("no such creature entry %u",m_spellInfo->EffectMiscValue[i]);
3590 delete spawnCreature;
3591 return;
3594 float px, py, pz;
3595 // If dest location if present
3596 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
3598 // Summon 1 unit in dest location
3599 if (count == 0)
3601 px = m_targets.m_destX;
3602 py = m_targets.m_destY;
3603 pz = m_targets.m_destZ;
3605 // Summon in random point all other units if location present
3606 else
3607 m_caster->GetRandomPoint(center_x,center_y,center_z,radius,px,py,pz);
3609 // Summon if dest location not present near caster
3610 else
3611 m_caster->GetClosePoint(px,py,pz,spawnCreature->GetObjectSize());
3613 spawnCreature->Relocate(px,py,pz,m_caster->GetOrientation());
3615 if(!spawnCreature->IsPositionValid())
3617 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not created base at creature. Suggested coordinates isn't valid (X: %d Y: ^%d)", spawnCreature->GetGUIDLow(), spawnCreature->GetEntry(), spawnCreature->GetPositionX(), spawnCreature->GetPositionY());
3618 delete spawnCreature;
3619 return;
3622 if(duration > 0)
3623 spawnCreature->SetDuration(duration);
3625 spawnCreature->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
3626 spawnCreature->setPowerType(POWER_MANA);
3627 spawnCreature->SetUInt32Value(UNIT_NPC_FLAGS , 0);
3628 spawnCreature->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
3629 spawnCreature->SetUInt32Value(UNIT_FIELD_FLAGS,0);
3630 spawnCreature->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
3631 spawnCreature->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,0);
3632 spawnCreature->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
3633 spawnCreature->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
3635 spawnCreature->InitStatsForLevel(level);
3636 spawnCreature->GetCharmInfo()->SetPetNumber(pet_number, false);
3638 spawnCreature->AIM_Initialize();
3640 if(m_caster->GetTypeId()==TYPEID_PLAYER)
3641 ((Player*)m_caster)->AddGuardian(spawnCreature);
3643 map->Add((Creature*)spawnCreature);
3647 void Spell::EffectTeleUnitsFaceCaster(uint32 i)
3649 if(!unitTarget)
3650 return;
3652 if(unitTarget->isInFlight())
3653 return;
3655 uint32 mapid = m_caster->GetMapId();
3656 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
3658 float fx,fy,fz;
3659 m_caster->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
3661 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3662 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, -m_caster->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
3663 else
3664 MapManager::Instance().GetMap(mapid, m_caster)->CreatureRelocation((Creature*)m_caster, fx, fy, fz, -m_caster->GetOrientation());
3667 void Spell::EffectLearnSkill(uint32 i)
3669 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3670 return;
3672 if(damage < 0)
3673 return;
3675 uint32 skillid = m_spellInfo->EffectMiscValue[i];
3676 uint16 skillval = ((Player*)unitTarget)->GetPureSkillValue(skillid);
3677 ((Player*)unitTarget)->SetSkill(skillid, skillval?skillval:1, damage*75);
3680 void Spell::EffectAddHonor(uint32 /*i*/)
3682 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3683 return;
3685 sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, this->damage, ((Player*)unitTarget)->GetGUIDLow());
3687 // TODO: find formula for honor reward based on player's level!
3689 // now fixed only for level 70 players:
3690 if (((Player*)unitTarget)->getLevel() == 70)
3691 ((Player*)unitTarget)->RewardHonor(NULL, 1, this->damage);
3694 void Spell::EffectTradeSkill(uint32 /*i*/)
3696 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
3697 return;
3698 // uint32 skillid = m_spellInfo->EffectMiscValue[i];
3699 // uint16 skillmax = ((Player*)unitTarget)->(skillid);
3700 // ((Player*)unitTarget)->SetSkill(skillid,skillval?skillval:1,skillmax+75);
3703 void Spell::EffectEnchantItemPerm(uint32 i)
3705 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3706 return;
3707 if (!itemTarget)
3708 return;
3710 Player* p_caster = (Player*)m_caster;
3712 p_caster->UpdateCraftSkill(m_spellInfo->Id);
3714 if (m_spellInfo->EffectMiscValue[i])
3716 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3718 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3719 if(!pEnchant)
3720 return;
3722 // item can be in trade slot and have owner diff. from caster
3723 Player* item_owner = itemTarget->GetOwner();
3724 if(!item_owner)
3725 return;
3727 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3728 sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
3729 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3730 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3731 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3733 // remove old enchanting before applying new if equipped
3734 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
3736 itemTarget->SetEnchantment(PERM_ENCHANTMENT_SLOT, enchant_id, 0, 0);
3738 // add new enchanting if equipped
3739 item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,true);
3743 void Spell::EffectEnchantItemTmp(uint32 i)
3745 if(m_caster->GetTypeId() != TYPEID_PLAYER)
3746 return;
3748 Player* p_caster = (Player*)m_caster;
3750 if(!itemTarget)
3751 return;
3753 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
3755 // Shaman Rockbiter Weapon
3756 if(i==0 && m_spellInfo->Effect[1]==SPELL_EFFECT_DUMMY)
3758 int32 enchnting_damage = m_currentBasePoints[1]+1;
3760 // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value
3761 // with already applied percent bonus from Elemental Weapons talent
3762 // Note: damage calculated (correctly) with rounding int32(float(v)) but
3763 // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime
3764 switch(enchnting_damage)
3766 // Rank 1
3767 case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2]
3768 // Rank 2
3769 case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4]
3770 case 5: enchant_id = 3025; break; // 20%
3771 // Rank 3
3772 case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6]
3773 case 7: enchant_id = 3027; break; // 20%
3774 // Rank 4
3775 case 9: enchant_id = 3032; break; // 0% [ 7% == 6]
3776 case 10: enchant_id = 503; break; // 14%
3777 case 11: enchant_id = 3031; break; // 20%
3778 // Rank 5
3779 case 15: enchant_id = 3035; break; // 0%
3780 case 16: enchant_id = 1663; break; // 7%
3781 case 17: enchant_id = 3033; break; // 14%
3782 case 18: enchant_id = 3034; break; // 20%
3783 // Rank 6
3784 case 28: enchant_id = 3038; break; // 0%
3785 case 29: enchant_id = 683; break; // 7%
3786 case 31: enchant_id = 3036; break; // 14%
3787 case 33: enchant_id = 3037; break; // 20%
3788 // Rank 7
3789 case 40: enchant_id = 3041; break; // 0%
3790 case 42: enchant_id = 1664; break; // 7%
3791 case 45: enchant_id = 3039; break; // 14%
3792 case 48: enchant_id = 3040; break; // 20%
3793 // Rank 8
3794 case 49: enchant_id = 3044; break; // 0%
3795 case 52: enchant_id = 2632; break; // 7%
3796 case 55: enchant_id = 3042; break; // 14%
3797 case 58: enchant_id = 3043; break; // 20%
3798 // Rank 9
3799 case 62: enchant_id = 2633; break; // 0%
3800 case 66: enchant_id = 3018; break; // 7%
3801 case 70: enchant_id = 3019; break; // 14%
3802 case 74: enchant_id = 3020; break; // 20%
3803 default:
3804 sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage);
3805 return;
3809 if (!enchant_id)
3811 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id",m_spellInfo->Id,i);
3812 return;
3815 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
3816 if(!pEnchant)
3818 sLog.outError("Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ",m_spellInfo->Id,i,enchant_id);
3819 return;
3822 // select enchantment duration
3823 uint32 duration;
3825 // rogue family enchantments exception by duration
3826 if(m_spellInfo->Id==38615)
3827 duration = 1800; // 30 mins
3828 // other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
3829 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE)
3830 duration = 3600; // 1 hour
3831 // shaman family enchantments
3832 else if(m_spellInfo->SpellFamilyName==SPELLFAMILY_SHAMAN)
3833 duration = 1800; // 30 mins
3834 // other cases with this SpellVisual already selected
3835 else if(m_spellInfo->SpellVisual==215)
3836 duration = 1800; // 30 mins
3837 // some fishing pole bonuses
3838 else if(m_spellInfo->SpellVisual==563)
3839 duration = 600; // 10 mins
3840 // shaman rockbiter enchantments
3841 else if(m_spellInfo->SpellVisual==0)
3842 duration = 1800; // 30 mins
3843 else if(m_spellInfo->Id==29702)
3844 duration = 300; // 5 mins
3845 else if(m_spellInfo->Id==37360)
3846 duration = 300; // 5 mins
3847 // default case
3848 else
3849 duration = 3600; // 1 hour
3851 // item can be in trade slot and have owner diff. from caster
3852 Player* item_owner = itemTarget->GetOwner();
3853 if(!item_owner)
3854 return;
3856 if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
3857 sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
3858 p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
3859 itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
3860 item_owner->GetName(),item_owner->GetSession()->GetAccountId());
3862 // remove old enchanting before applying new if equipped
3863 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
3865 itemTarget->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, duration*1000, 0);
3867 // add new enchanting if equipped
3868 item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,true);
3871 void Spell::EffectTameCreature(uint32 /*i*/)
3873 if(m_caster->GetPetGUID())
3874 return;
3876 if(!unitTarget)
3877 return;
3879 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
3880 return;
3882 Creature* creatureTarget = (Creature*)unitTarget;
3884 if(creatureTarget->isPet())
3885 return;
3887 if(m_caster->getClass() != CLASS_HUNTER)
3888 return;
3890 // cast finish successfully
3891 //SendChannelUpdate(0);
3892 finish();
3894 Pet* pet = m_caster->CreateTamedPetFrom(creatureTarget,m_spellInfo->Id);
3896 // kill original creature
3897 creatureTarget->setDeathState(JUST_DIED);
3898 creatureTarget->RemoveCorpse();
3899 creatureTarget->SetHealth(0); // just for nice GM-mode view
3901 // prepare visual effect for levelup
3902 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
3904 // add to world
3905 MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
3907 // visual effect for levelup
3908 pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
3910 // caster have pet now
3911 m_caster->SetPet(pet);
3913 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3915 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
3916 ((Player*)m_caster)->PetSpellInitialize();
3920 void Spell::EffectSummonPet(uint32 i)
3922 uint32 petentry = m_spellInfo->EffectMiscValue[i];
3924 Pet *OldSummon = m_caster->GetPet();
3926 // if pet requested type already exist
3927 if( OldSummon )
3929 if(petentry == 0 || OldSummon->GetEntry() == petentry)
3931 // pet in corpse state can't be summoned
3932 if( OldSummon->isDead() )
3933 return;
3935 MapManager::Instance().GetMap(OldSummon->GetMapId(), OldSummon)->Remove((Creature*)OldSummon,false);
3936 OldSummon->SetMapId(m_caster->GetMapId());
3938 float px, py, pz;
3939 m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
3941 OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
3942 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->Add((Creature*)OldSummon);
3944 if(m_caster->GetTypeId() == TYPEID_PLAYER && OldSummon->isControlled() )
3946 ((Player*)m_caster)->PetSpellInitialize();
3948 return;
3951 if(m_caster->GetTypeId() == TYPEID_PLAYER)
3952 ((Player*)m_caster)->RemovePet(OldSummon,(OldSummon->getPetType()==HUNTER_PET ? PET_SAVE_AS_DELETED : PET_SAVE_NOT_IN_SLOT),false);
3953 else
3954 return;
3957 Pet* NewSummon = new Pet;
3959 // petentry==0 for hunter "call pet" (current pet summoned if any)
3960 if(NewSummon->LoadPetFromDB(m_caster,petentry))
3962 if(NewSummon->getPetType()==SUMMON_PET)
3964 // Remove Demonic Sacrifice auras (known pet)
3965 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
3966 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
3968 if((*itr)->GetModifier()->m_miscvalue==2228)
3970 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
3971 itr = auraClassScripts.begin();
3973 else
3974 ++itr;
3978 return;
3981 // not error in case fail hunter call pet
3982 if(!petentry)
3984 delete NewSummon;
3985 return;
3988 CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(petentry);
3990 if(!cInfo)
3992 sLog.outError("EffectSummonPet: creature entry %u not found.",petentry);
3993 delete NewSummon;
3994 return;
3997 Map *map = m_caster->GetMap();
3998 uint32 pet_number = objmgr.GeneratePetNumber();
3999 if(!NewSummon->Create(objmgr.GenerateLowGuid(HIGHGUID_PET), map, petentry, pet_number))
4001 delete NewSummon;
4002 return;
4005 float px, py, pz;
4006 m_caster->GetClosePoint(px, py, pz, NewSummon->GetObjectSize());
4008 NewSummon->Relocate(px, py, pz, m_caster->GetOrientation());
4010 if(!NewSummon->IsPositionValid())
4012 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", NewSummon->GetGUIDLow(), NewSummon->GetEntry(), NewSummon->GetPositionX(), NewSummon->GetPositionY());
4013 delete NewSummon;
4014 return;
4017 uint32 petlevel = m_caster->getLevel();
4018 NewSummon->setPetType(SUMMON_PET);
4020 uint32 faction = m_caster->getFaction();
4021 if(m_caster->GetTypeId() == TYPEID_UNIT)
4023 if ( ((Creature*)m_caster)->isTotem() )
4024 NewSummon->GetCharmInfo()->SetReactState(REACT_AGGRESSIVE);
4025 else
4026 NewSummon->GetCharmInfo()->SetReactState(REACT_DEFENSIVE);
4029 NewSummon->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, m_caster->GetGUID());
4030 NewSummon->SetUInt64Value(UNIT_FIELD_CREATEDBY, m_caster->GetGUID());
4031 NewSummon->SetUInt32Value(UNIT_NPC_FLAGS , 0);
4032 NewSummon->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction);
4033 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_0,2048);
4034 NewSummon->SetUInt32Value(UNIT_FIELD_BYTES_1,0);
4035 NewSummon->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP,time(NULL));
4036 NewSummon->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE,0);
4037 NewSummon->SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP,1000);
4038 NewSummon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
4040 NewSummon->GetCharmInfo()->SetPetNumber(pet_number, true);
4041 // this enables pet details window (Shift+P)
4043 // this enables popup window (pet dismiss, cancel), hunter pet additional flags set later
4044 NewSummon->SetUInt32Value(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
4046 NewSummon->InitStatsForLevel( petlevel);
4047 NewSummon->InitPetCreateSpells();
4049 if(NewSummon->getPetType()==SUMMON_PET)
4051 // Remove Demonic Sacrifice auras (new pet)
4052 Unit::AuraList const& auraClassScripts = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4053 for(Unit::AuraList::const_iterator itr = auraClassScripts.begin();itr!=auraClassScripts.end();)
4055 if((*itr)->GetModifier()->m_miscvalue==2228)
4057 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4058 itr = auraClassScripts.begin();
4060 else
4061 ++itr;
4064 // generate new name for summon pet
4065 std::string new_name=objmgr.GeneratePetName(petentry);
4066 if(!new_name.empty())
4067 NewSummon->SetName(new_name);
4069 else if(NewSummon->getPetType()==HUNTER_PET)
4070 NewSummon->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
4072 NewSummon->AIM_Initialize();
4073 NewSummon->SetHealth(NewSummon->GetMaxHealth());
4074 NewSummon->SetPower(POWER_MANA, NewSummon->GetMaxPower(POWER_MANA));
4076 map->Add((Creature*)NewSummon);
4078 m_caster->SetPet(NewSummon);
4079 sLog.outDebug("New Pet has guid %u", NewSummon->GetGUIDLow());
4081 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4083 NewSummon->SavePetToDB(PET_SAVE_AS_CURRENT);
4084 ((Player*)m_caster)->PetSpellInitialize();
4088 void Spell::EffectLearnPetSpell(uint32 i)
4090 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4091 return;
4093 Player *_player = (Player*)m_caster;
4095 Pet *pet = _player->GetPet();
4096 if(!pet)
4097 return;
4098 if(!pet->isAlive())
4099 return;
4101 SpellEntry const *learn_spellproto = sSpellStore.LookupEntry(m_spellInfo->EffectTriggerSpell[i]);
4102 if(!learn_spellproto)
4103 return;
4105 pet->SetTP(pet->m_TrainingPoints - pet->GetTPForSpell(learn_spellproto->Id));
4106 pet->learnSpell(learn_spellproto->Id);
4108 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
4109 _player->PetSpellInitialize();
4112 void Spell::EffectTaunt(uint32 /*i*/)
4114 // this effect use before aura Taunt apply for prevent taunt already attacking target
4115 // for spell as marked "non effective at already attacking target"
4116 if(unitTarget && unitTarget->GetTypeId() != TYPEID_PLAYER)
4118 if(unitTarget->getVictim()==m_caster)
4120 SendCastResult(SPELL_FAILED_DONT_REPORT);
4121 return;
4125 // Also use this effect to set the taunter's threat to the taunted creature's highest value
4126 if(unitTarget->CanHaveThreatList() && unitTarget->getThreatManager().getCurrentVictim())
4127 unitTarget->getThreatManager().addThreat(m_caster,unitTarget->getThreatManager().getCurrentVictim()->getThreat());
4130 void Spell::EffectWeaponDmg(uint32 i)
4132 if(!unitTarget)
4133 return;
4134 if(!unitTarget->isAlive())
4135 return;
4137 // multiple weapon dmg effect workaround
4138 // execute only the last weapon damage
4139 // and handle all effects at once
4140 for (int j = 0; j < 3; j++)
4142 switch(m_spellInfo->Effect[j])
4144 case SPELL_EFFECT_WEAPON_DAMAGE:
4145 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4146 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4147 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4148 if (j < i) // we must calculate only at last weapon effect
4149 return;
4150 break;
4154 // some spell specific modifiers
4155 bool customBonusDamagePercentMod = false;
4156 float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
4157 float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
4158 float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
4159 bool normalized = false;
4161 int32 spell_bonus = 0; // bonus specific for spell
4162 switch(m_spellInfo->SpellFamilyName)
4164 case SPELLFAMILY_WARRIOR:
4166 // Whirlwind, single only spell with 2 weapon white damage apply if have
4167 if(m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & 0x00000400000000LL))
4169 if(((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK,true))
4170 spell_bonus += m_caster->CalculateDamage (OFF_ATTACK, normalized);
4172 // Devastate bonus and sunder armor refresh
4173 else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
4175 customBonusDamagePercentMod = true;
4176 bonusDamagePercentMod = 0.0f; // only applied if auras found
4178 Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
4179 for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
4181 SpellEntry const *proto = (*itr)->GetSpellProto();
4182 if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
4184 int32 duration = GetSpellDuration(proto);
4185 (*itr)->SetAuraDuration(duration);
4186 (*itr)->UpdateAuraDuration();
4187 bonusDamagePercentMod += 1.0f; // +100%
4191 break;
4193 case SPELLFAMILY_ROGUE:
4195 // Ambush
4196 if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
4198 customBonusDamagePercentMod = true;
4199 bonusDamagePercentMod = 2.5f; // 250%
4201 // Mutilate (for each hand)
4202 else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
4204 bool found = false;
4205 // fast check
4206 if(unitTarget->HasAuraState(AURA_STATE_DEADLY_POISON))
4207 found = true;
4208 // full aura scan
4209 else
4211 Unit::AuraMap const& auras = unitTarget->GetAuras();
4212 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr!=auras.end(); ++itr)
4214 if(itr->second->GetSpellProto()->Dispel == DISPEL_POISON)
4216 found = true;
4217 break;
4222 if(found)
4223 totalDamagePercentMod *= 1.5f; // 150% if poisoned
4225 break;
4227 case SPELLFAMILY_PALADIN:
4229 // Seal of Command - receive benefit from Spell Damage and Healing
4230 if(m_spellInfo->SpellFamilyFlags & 0x00000002000000LL)
4232 spell_bonus += int32(0.20f*m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)));
4233 spell_bonus += int32(0.29f*m_caster->SpellBaseDamageBonusForVictim(GetSpellSchoolMask(m_spellInfo), unitTarget));
4235 break;
4237 case SPELLFAMILY_SHAMAN:
4239 // Skyshatter Harness item set bonus
4240 // Stormstrike
4241 if(m_spellInfo->SpellFamilyFlags & 0x001000000000LL)
4243 Unit::AuraList const& m_OverrideClassScript = m_caster->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
4244 for(Unit::AuraList::const_iterator i = m_OverrideClassScript.begin(); i != m_OverrideClassScript.end(); ++i)
4246 // Stormstrike AP Buff
4247 if ( (*i)->GetModifier()->m_miscvalue == 5634 )
4249 m_caster->CastSpell(m_caster,38430,true,NULL,*i);
4250 break;
4257 int32 fixed_bonus = 0;
4258 for (int j = 0; j < 3; j++)
4260 switch(m_spellInfo->Effect[j])
4262 case SPELL_EFFECT_WEAPON_DAMAGE:
4263 case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
4264 fixed_bonus += CalculateDamage(j,unitTarget);
4265 break;
4266 case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
4267 fixed_bonus += CalculateDamage(j,unitTarget);
4268 normalized = true;
4269 break;
4270 case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
4271 weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
4273 // applied only to prev.effects fixed damage
4274 if(customBonusDamagePercentMod)
4275 fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
4276 else
4277 fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
4278 break;
4279 default:
4280 break; // not weapon damage effect, just skip
4284 // non-weapon damage
4285 int32 bonus = spell_bonus + fixed_bonus;
4287 // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
4288 if(bonus)
4290 UnitMods unitMod;
4291 switch(m_attackType)
4293 default:
4294 case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break;
4295 case OFF_ATTACK: unitMod = UNIT_MOD_DAMAGE_OFFHAND; break;
4296 case RANGED_ATTACK: unitMod = UNIT_MOD_DAMAGE_RANGED; break;
4299 float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
4300 bonus = int32(bonus*weapon_total_pct);
4303 // + weapon damage with applied weapon% dmg to base weapon damage in call
4304 bonus += int32(m_caster->CalculateDamage(m_attackType, normalized)*weaponDamagePercentMod);
4306 // total damage
4307 bonus = int32(bonus*totalDamagePercentMod);
4309 // prevent negative damage
4310 uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
4312 const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
4314 uint32 hitInfo = 0;
4315 VictimState victimState = VICTIMSTATE_NORMAL;
4316 uint32 blocked_dmg = 0;
4317 uint32 absorbed_dmg = 0;
4318 uint32 resisted_dmg = 0;
4319 CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
4321 m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
4323 if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
4324 m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
4326 bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
4327 m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
4329 if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
4331 eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
4333 else
4335 cleanDamage.damage += eff_damage;
4336 eff_damage = 0;
4339 // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
4340 m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
4342 // Hemorrhage
4343 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
4345 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4346 ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
4349 // Mangle (Cat): CP
4350 if(m_spellInfo->SpellFamilyName==SPELLFAMILY_DRUID && (m_spellInfo->SpellFamilyFlags==0x0000040000000000LL))
4352 if(m_caster->GetTypeId()==TYPEID_PLAYER)
4353 ((Player*)m_caster)->AddComboPoints(unitTarget,1);
4356 // take ammo
4357 if(m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
4359 Item *pItem = ((Player*)m_caster)->GetWeaponForAttack( RANGED_ATTACK );
4361 // wands don't have ammo
4362 if(!pItem || pItem->IsBroken() || pItem->GetProto()->SubClass==ITEM_SUBCLASS_WEAPON_WAND)
4363 return;
4365 if( pItem->GetProto()->InventoryType == INVTYPE_THROWN )
4367 if(pItem->GetMaxStackCount()==1)
4369 // decrease durability for non-stackable throw weapon
4370 ((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
4372 else
4374 // decrease items amount for stackable throw weapon
4375 uint32 count = 1;
4376 ((Player*)m_caster)->DestroyItemCount( pItem, count, true);
4379 else if(uint32 ammo = ((Player*)m_caster)->GetUInt32Value(PLAYER_AMMO_ID))
4380 ((Player*)m_caster)->DestroyItemCount(ammo, 1, true);
4384 void Spell::EffectThreat(uint32 /*i*/)
4386 if(!unitTarget || !unitTarget->isAlive() || !m_caster->isAlive())
4387 return;
4389 if(!unitTarget->CanHaveThreatList())
4390 return;
4392 unitTarget->AddThreat(m_caster, float(damage));
4395 void Spell::EffectHealMaxHealth(uint32 /*i*/)
4397 if(!unitTarget)
4398 return;
4399 if(!unitTarget->isAlive())
4400 return;
4402 uint32 heal = m_caster->GetMaxHealth();
4404 int32 gain = unitTarget->ModifyHealth(heal);
4405 unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
4407 m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
4410 void Spell::EffectInterruptCast(uint32 /*i*/)
4412 if(!unitTarget)
4413 return;
4414 if(!unitTarget->isAlive())
4415 return;
4417 // TODO: not all spells that used this effect apply cooldown at school spells
4418 // also exist case: apply cooldown to interrupted cast only and to all spells
4419 for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
4421 if (unitTarget->m_currentSpells[i])
4423 // check if we can interrupt spell
4424 if ( unitTarget->m_currentSpells[i]->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT && unitTarget->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE )
4426 unitTarget->ProhibitSpellScholl(GetSpellSchoolMask(unitTarget->m_currentSpells[i]->m_spellInfo), GetSpellDuration(m_spellInfo));
4427 unitTarget->InterruptSpell(i,false);
4433 void Spell::EffectSummonObjectWild(uint32 i)
4435 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4437 GameObject* pGameObj = new GameObject;
4439 WorldObject* target = focusObject;
4440 if( !target )
4441 target = m_caster;
4443 float x,y,z;
4444 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
4446 x = m_targets.m_destX;
4447 y = m_targets.m_destY;
4448 z = m_targets.m_destZ;
4450 else
4451 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
4453 Map *map = target->GetMap();
4455 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4456 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4458 delete pGameObj;
4459 return;
4462 int32 duration = GetSpellDuration(m_spellInfo);
4463 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4464 pGameObj->SetSpellId(m_spellInfo->Id);
4466 if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
4467 m_caster->AddGameObject(pGameObj);
4468 map->Add(pGameObj);
4470 if(pGameObj->GetMapId() == 489 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //WS
4472 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4474 Player *pl = (Player*)m_caster;
4475 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4476 if(bg && bg->GetTypeID()==BATTLEGROUND_WS && bg->GetStatus() == STATUS_IN_PROGRESS)
4478 uint32 team = ALLIANCE;
4480 if(pl->GetTeam() == team)
4481 team = HORDE;
4483 ((BattleGroundWS*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID(),team);
4488 if(pGameObj->GetMapId() == 566 && pGameObj->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP) //EY
4490 if(m_caster->GetTypeId() == TYPEID_PLAYER)
4492 BattleGround* bg = ((Player *)m_caster)->GetBattleGround();
4493 if(bg && bg->GetTypeID()==BATTLEGROUND_EY && bg->GetStatus() == STATUS_IN_PROGRESS)
4495 ((BattleGroundEY*)bg)->SetDroppedFlagGUID(pGameObj->GetGUID());
4500 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
4502 GameObject* linkedGO = new GameObject;
4503 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
4504 x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
4506 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4507 linkedGO->SetSpellId(m_spellInfo->Id);
4509 m_caster->AddGameObject(linkedGO);
4510 map->Add(linkedGO);
4512 else
4514 delete linkedGO;
4515 linkedGO = NULL;
4516 return;
4521 void Spell::EffectScriptEffect(uint32 effIndex)
4523 // TODO: we must implement hunter pet summon at login there (spell 6962)
4525 // by spell id
4526 switch(m_spellInfo->Id)
4528 // Bending Shinbone
4529 case 8856:
4531 if(!itemTarget && m_caster->GetTypeId()!=TYPEID_PLAYER)
4532 return;
4534 uint32 spell_id = 0;
4535 switch(urand(1,5))
4537 case 1: spell_id = 8854; break;
4538 default: spell_id = 8855; break;
4541 m_caster->CastSpell(m_caster,spell_id,true,NULL);
4542 return;
4545 // Healthstone creating spells
4546 case 6201:
4547 case 6202:
4548 case 5699:
4549 case 11729:
4550 case 11730:
4551 case 27230:
4553 uint32 itemtype;
4554 uint32 rank = 0;
4555 Unit::AuraList const& mDummyAuras = unitTarget->GetAurasByType(SPELL_AURA_DUMMY);
4556 for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
4558 if((*i)->GetId() == 18692)
4560 rank = 1;
4561 break;
4563 else if((*i)->GetId() == 18693)
4565 rank = 2;
4566 break;
4570 static uint32 const itypes[6][3] = {
4571 { 5512,19004,19005}, // Minor Healthstone
4572 { 5511,19006,19007}, // Lesser Healthstone
4573 { 5509,19008,19009}, // Healthstone
4574 { 5510,19010,19011}, // Greater Healthstone
4575 { 9421,19012,19013}, // Major Healthstone
4576 {22103,22104,22105} // Master Healthstone
4579 switch(m_spellInfo->Id)
4581 case 6201: itemtype=itypes[0][rank];break; // Minor Healthstone
4582 case 6202: itemtype=itypes[1][rank];break; // Lesser Healthstone
4583 case 5699: itemtype=itypes[2][rank];break; // Healthstone
4584 case 11729: itemtype=itypes[3][rank];break; // Greater Healthstone
4585 case 11730: itemtype=itypes[4][rank];break; // Major Healthstone
4586 case 27230: itemtype=itypes[5][rank];break; // Master Healthstone
4587 default:
4588 return;
4590 DoCreateItem( effIndex, itemtype );
4591 return;
4593 // Brittle Armor - need remove one 24575 Brittle Armor aura
4594 case 24590:
4595 unitTarget->RemoveSingleAuraFromStack(24575, 0);
4596 unitTarget->RemoveSingleAuraFromStack(24575, 1);
4597 return;
4598 // Mercurial Shield - need remove one 26464 Mercurial Shield aura
4599 case 26465:
4600 unitTarget->RemoveSingleAuraFromStack(26464, 0);
4601 return;
4602 // Orb teleport spells
4603 case 25140:
4604 case 25143:
4605 case 25650:
4606 case 25652:
4607 case 29128:
4608 case 29129:
4609 case 35376:
4610 case 35727:
4612 if(!unitTarget)
4613 return;
4615 uint32 spellid;
4616 switch(m_spellInfo->Id)
4618 case 25140: spellid = 32571; break;
4619 case 25143: spellid = 32572; break;
4620 case 25650: spellid = 30140; break;
4621 case 25652: spellid = 30141; break;
4622 case 29128: spellid = 32568; break;
4623 case 29129: spellid = 32569; break;
4624 case 35376: spellid = 25649; break;
4625 case 35727: spellid = 35730; break;
4626 default:
4627 return;
4630 unitTarget->CastSpell(unitTarget,spellid,false);
4631 return;
4634 // Shadow Flame (All script effects, not just end ones to prevent player from dodging the last triggered spell)
4635 case 22539:
4636 case 22972:
4637 case 22975:
4638 case 22976:
4639 case 22977:
4640 case 22978:
4641 case 22979:
4642 case 22980:
4643 case 22981:
4644 case 22982:
4645 case 22983:
4646 case 22984:
4647 case 22985:
4649 if(!unitTarget || !unitTarget->isAlive())
4650 return;
4652 // Onyxia Scale Cloak
4653 if(unitTarget->GetDummyAura(22683))
4654 return;
4656 // Shadow Flame
4657 m_caster->CastSpell(unitTarget, 22682, true);
4658 return;
4660 break;
4662 // Summon Black Qiraji Battle Tank
4663 case 26656:
4665 if(!unitTarget)
4666 return;
4668 // Prevent stacking of mounts
4669 unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
4671 // Two separate mounts depending on area id (allows use both in and out of specific instance)
4672 if (unitTarget->GetAreaId() == 3428)
4673 unitTarget->CastSpell(unitTarget, 25863, false);
4674 else
4675 unitTarget->CastSpell(unitTarget, 26655, false);
4676 break;
4678 // Piccolo of the Flaming Fire
4679 case 17512:
4681 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4682 return;
4683 unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
4684 break;
4687 // Dreaming Glory
4688 case 28698:
4690 if(!unitTarget)
4691 return;
4692 unitTarget->CastSpell(unitTarget, 28694, true);
4693 break;
4696 // Netherbloom
4697 case 28702:
4699 if(!unitTarget)
4700 return;
4701 // 25% chance of casting a random buff
4702 if(roll_chance_i(75))
4703 return;
4705 // triggered spells are 28703 to 28707
4706 // Note: some sources say, that there was the possibility of
4707 // receiving a debuff. However, this seems to be removed by a patch.
4708 const uint32 spellid = 28703;
4710 // don't overwrite an existing aura
4711 for(uint8 i=0; i<5; i++)
4712 if(unitTarget->HasAura(spellid+i, 0))
4713 return;
4714 unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
4715 break;
4718 // Nightmare Vine
4719 case 28720:
4721 if(!unitTarget)
4722 return;
4723 // 25% chance of casting Nightmare Pollen
4724 if(roll_chance_i(75))
4725 return;
4726 unitTarget->CastSpell(unitTarget, 28721, true);
4727 break;
4730 // Mirren's Drinking Hat
4731 case 29830:
4733 uint32 item = 0;
4734 switch ( urand(1,6) )
4736 case 1: case 2: case 3: item = 23584; break;// Loch Modan Lager
4737 case 4: case 5: item = 23585; break;// Stouthammer Lite
4738 case 6: item = 23586; break;// Aerie Peak Pale Ale
4740 if (item)
4741 DoCreateItem(effIndex,item);
4742 break;
4744 // Improved Sprint
4745 case 30918:
4747 // Removes snares and roots.
4748 uint32 mechanic_mask = (1<<MECHANIC_ROOT) | (1<<MECHANIC_SNARE);
4749 Unit::AuraMap& Auras = unitTarget->GetAuras();
4750 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
4752 next = iter;
4753 ++next;
4754 Aura *aur = iter->second;
4755 if (!aur->IsPositive()) //only remove negative spells
4757 // check for mechanic mask
4758 if(GetSpellMechanicMask(aur->GetSpellProto(), aur->GetEffIndex()) & mechanic_mask)
4760 unitTarget->RemoveAurasDueToSpell(aur->GetId());
4761 if(Auras.empty())
4762 break;
4763 else
4764 next = Auras.begin();
4768 break;
4770 case 41126: // Flame Crash
4772 if(!unitTarget)
4773 return;
4775 unitTarget->CastSpell(unitTarget, 41131, true);
4776 break;
4778 case 44876: // Force Cast - Portal Effect: Sunwell Isle
4780 if(!unitTarget)
4781 return;
4783 unitTarget->CastSpell(unitTarget, 44870, true);
4784 break;
4787 // Goblin Weather Machine
4788 case 46203:
4790 if(!unitTarget)
4791 return;
4793 uint32 spellId;
4794 switch(rand()%4)
4796 case 0:
4797 spellId=46740;
4798 break;
4799 case 1:
4800 spellId=46739;
4801 break;
4802 case 2:
4803 spellId=46738;
4804 break;
4805 case 3:
4806 spellId=46736;
4807 break;
4809 unitTarget->CastSpell(unitTarget, spellId, true);
4810 break;
4812 //5,000 Gold
4813 case 46642:
4815 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
4816 return;
4818 ((Player*)unitTarget)->ModifyMoney(50000000);
4820 break;
4824 if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN )
4826 switch(m_spellInfo->SpellFamilyFlags)
4828 // Judgement
4829 case 0x800000:
4831 if(!unitTarget || !unitTarget->isAlive())
4832 return;
4833 uint32 spellId2 = 0;
4835 // all seals have aura dummy
4836 Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4837 for(Unit::AuraList::const_iterator itr = m_dummyAuras.begin(); itr != m_dummyAuras.end(); ++itr)
4839 SpellEntry const *spellInfo = (*itr)->GetSpellProto();
4841 // search seal (all seals have judgement's aura dummy spell id in 2 effect
4842 if ( !spellInfo || !IsSealSpell((*itr)->GetSpellProto()) || (*itr)->GetEffIndex() != 2 )
4843 continue;
4845 // must be calculated base at raw base points in spell proto, GetModifier()->m_value for S.Righteousness modified by SPELLMOD_DAMAGE
4846 spellId2 = (*itr)->GetSpellProto()->EffectBasePoints[2]+1;
4848 if(spellId2 <= 1)
4849 continue;
4851 // found, remove seal
4852 m_caster->RemoveAurasDueToSpell((*itr)->GetId());
4854 // Sanctified Judgement
4855 Unit::AuraList const& m_auras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
4856 for(Unit::AuraList::const_iterator i = m_auras.begin(); i != m_auras.end(); ++i)
4858 if ((*i)->GetSpellProto()->SpellIconID == 205 && (*i)->GetSpellProto()->Attributes == 0x01D0LL)
4860 int32 chance = (*i)->GetModifier()->m_amount;
4861 if ( roll_chance_i(chance) )
4863 int32 mana = spellInfo->manaCost;
4864 if ( Player* modOwner = m_caster->GetSpellModOwner() )
4865 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, mana);
4866 mana = int32(mana* 0.8f);
4867 m_caster->CastCustomSpell(m_caster,31930,&mana,NULL,NULL,true,NULL,*i);
4869 break;
4873 break;
4876 m_caster->CastSpell(unitTarget,spellId2,true);
4877 return;
4882 // normal DB scripted effect
4883 if(!unitTarget)
4884 return;
4886 sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
4887 sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
4890 void Spell::EffectSanctuary(uint32 /*i*/)
4892 if(!unitTarget)
4893 return;
4894 //unitTarget->CombatStop();
4896 unitTarget->CombatStop();
4897 unitTarget->getHostilRefManager().deleteReferences(); // stop all fighting
4898 // Vanish allows to remove all threat and cast regular stealth so other spells can be used
4899 if(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & SPELLFAMILYFLAG_ROGUE_VANISH))
4901 ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
4905 void Spell::EffectAddComboPoints(uint32 /*i*/)
4907 if(!unitTarget)
4908 return;
4910 if(m_caster->GetTypeId() != TYPEID_PLAYER)
4911 return;
4913 if(damage <= 0)
4914 return;
4916 ((Player*)m_caster)->AddComboPoints(unitTarget, damage);
4919 void Spell::EffectDuel(uint32 i)
4921 if(!m_caster || !unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER || unitTarget->GetTypeId() != TYPEID_PLAYER)
4922 return;
4924 Player *caster = (Player*)m_caster;
4925 Player *target = (Player*)unitTarget;
4927 // caster or target already have requested duel
4928 if( caster->duel || target->duel || !target->GetSocial() || target->GetSocial()->HasIgnore(caster->GetGUIDLow()) )
4929 return;
4931 // Players can only fight a duel with each other outside (=not inside dungeons and not in capital cities)
4932 // Don't have to check the target's map since you cannot challenge someone across maps
4933 if( caster->GetMapId() != 0 && caster->GetMapId() != 1 && caster->GetMapId() != 530)
4935 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4936 return;
4939 AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetZoneId());
4940 if(casterAreaEntry && (casterAreaEntry->flags & AREA_FLAG_CAPITAL) )
4942 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4943 return;
4946 AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetZoneId());
4947 if(targetAreaEntry && (targetAreaEntry->flags & AREA_FLAG_CAPITAL) )
4949 SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here
4950 return;
4953 //CREATE DUEL FLAG OBJECT
4954 GameObject* pGameObj = new GameObject;
4956 uint32 gameobject_id = m_spellInfo->EffectMiscValue[i];
4958 Map *map = m_caster->GetMap();
4959 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map,
4960 m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2 ,
4961 m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2 ,
4962 m_caster->GetPositionZ(),
4963 m_caster->GetOrientation(), 0, 0, 0, 0, 0, 1))
4965 delete pGameObj;
4966 return;
4969 pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
4970 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
4971 int32 duration = GetSpellDuration(m_spellInfo);
4972 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
4973 pGameObj->SetSpellId(m_spellInfo->Id);
4975 m_caster->AddGameObject(pGameObj);
4976 map->Add(pGameObj);
4977 //END
4979 // Send request
4980 WorldPacket data(SMSG_DUEL_REQUESTED, 16);
4981 data << pGameObj->GetGUID();
4982 data << caster->GetGUID();
4983 caster->GetSession()->SendPacket(&data);
4984 target->GetSession()->SendPacket(&data);
4986 // create duel-info
4987 DuelInfo *duel = new DuelInfo;
4988 duel->initiator = caster;
4989 duel->opponent = target;
4990 duel->startTime = 0;
4991 duel->startTimer = 0;
4992 caster->duel = duel;
4994 DuelInfo *duel2 = new DuelInfo;
4995 duel2->initiator = caster;
4996 duel2->opponent = caster;
4997 duel2->startTime = 0;
4998 duel2->startTimer = 0;
4999 target->duel = duel2;
5001 caster->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5002 target->SetUInt64Value(PLAYER_DUEL_ARBITER,pGameObj->GetGUID());
5005 void Spell::EffectStuck(uint32 /*i*/)
5007 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5008 return;
5010 if(!sWorld.getConfig(CONFIG_CAST_UNSTUCK))
5011 return;
5013 Player* pTarget = (Player*)unitTarget;
5015 sLog.outDebug("Spell Effect: Stuck");
5016 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());
5018 if(pTarget->isInFlight())
5019 return;
5021 // homebind location is loaded always
5022 pTarget->TeleportTo(pTarget->m_homebindMapId,pTarget->m_homebindX,pTarget->m_homebindY,pTarget->m_homebindZ,pTarget->GetOrientation(), (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5024 // Stuck spell trigger Hearthstone cooldown
5025 SpellEntry const *spellInfo = sSpellStore.LookupEntry(8690);
5026 if(!spellInfo)
5027 return;
5028 Spell spell(pTarget,spellInfo,true,0);
5029 spell.SendSpellCooldown();
5032 void Spell::EffectSummonPlayer(uint32 /*i*/)
5034 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5035 return;
5037 // Evil Twin (ignore player summon, but hide this for summoner)
5038 if(unitTarget->GetDummyAura(23445))
5039 return;
5041 float x,y,z;
5042 m_caster->GetClosePoint(x,y,z,unitTarget->GetObjectSize());
5044 ((Player*)unitTarget)->SetSummonPoint(m_caster->GetMapId(),x,y,z);
5046 WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
5047 data << uint64(m_caster->GetGUID()); // summoner guid
5048 data << uint32(m_caster->GetZoneId()); // summoner zone
5049 data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
5050 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5053 static ScriptInfo generateActivateCommand()
5055 ScriptInfo si;
5056 si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
5057 return si;
5060 void Spell::EffectActivateObject(uint32 effect_idx)
5062 if(!gameObjTarget)
5063 return;
5065 static ScriptInfo activateCommand = generateActivateCommand();
5067 int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
5069 sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
5072 void Spell::EffectSummonTotem(uint32 i)
5074 uint8 slot = 0;
5075 switch(m_spellInfo->EffectMiscValueB[i])
5077 case SUMMON_TYPE_TOTEM_SLOT1: slot = 0; break;
5078 case SUMMON_TYPE_TOTEM_SLOT2: slot = 1; break;
5079 case SUMMON_TYPE_TOTEM_SLOT3: slot = 2; break;
5080 case SUMMON_TYPE_TOTEM_SLOT4: slot = 3; break;
5081 // Battle standard case
5082 case SUMMON_TYPE_TOTEM: slot = 254; break;
5083 // jewelery statue case, like totem without slot
5084 case SUMMON_TYPE_GUARDIAN: slot = 255; break;
5085 default: return;
5088 if(slot < MAX_TOTEM)
5090 uint64 guid = m_caster->m_TotemSlot[slot];
5091 if(guid != 0)
5093 Creature *OldTotem = ObjectAccessor::GetCreature(*m_caster, guid);
5094 if(OldTotem && OldTotem->isTotem())
5095 ((Totem*)OldTotem)->UnSummon();
5099 uint32 team = 0;
5100 if (m_caster->GetTypeId()==TYPEID_PLAYER)
5101 team = ((Player*)m_caster)->GetTeam();
5103 Totem* pTotem = new Totem;
5105 if(!pTotem->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), m_caster->GetMap(), m_spellInfo->EffectMiscValue[i], team ))
5107 delete pTotem;
5108 return;
5111 float angle = slot < MAX_TOTEM ? M_PI/MAX_TOTEM - (slot*2*M_PI/MAX_TOTEM) : 0;
5113 float x,y,z;
5114 m_caster->GetClosePoint(x,y,z,pTotem->GetObjectSize(),2.0f,angle);
5116 // totem must be at same Z in case swimming caster and etc.
5117 if( fabs( z - m_caster->GetPositionZ() ) > 5 )
5118 z = m_caster->GetPositionZ();
5120 pTotem->Relocate(x, y, z, m_caster->GetOrientation());
5122 if(slot < MAX_TOTEM)
5123 m_caster->m_TotemSlot[slot] = pTotem->GetGUID();
5125 pTotem->SetOwner(m_caster->GetGUID());
5126 pTotem->SetTypeBySummonSpell(m_spellInfo); // must be after Create call where m_spells initilized
5128 int32 duration=GetSpellDuration(m_spellInfo);
5129 if(Player* modOwner = m_caster->GetSpellModOwner())
5130 modOwner->ApplySpellMod(m_spellInfo->Id,SPELLMOD_DURATION, duration);
5131 pTotem->SetDuration(duration);
5133 if (damage) // if not spell info, DB values used
5135 pTotem->SetMaxHealth(damage);
5136 pTotem->SetHealth(damage);
5139 pTotem->SetUInt32Value(UNIT_CREATED_BY_SPELL,m_spellInfo->Id);
5140 pTotem->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_PVP_ATTACKABLE);
5142 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_MOD_FEAR,true);
5143 pTotem->ApplySpellImmune(m_spellInfo->Id,IMMUNITY_STATE,SPELL_AURA_TRANSFORM,true);
5145 pTotem->Summon(m_caster);
5147 if(slot < MAX_TOTEM && m_caster->GetTypeId() == TYPEID_PLAYER)
5149 WorldPacket data(SMSG_TOTEM_CREATED, 1+8+4+4);
5150 data << uint8(slot);
5151 data << uint64(pTotem->GetGUID());
5152 data << uint32(duration);
5153 data << uint32(m_spellInfo->Id);
5154 ((Player*)m_caster)->SendDirectMessage(&data);
5158 void Spell::EffectEnchantHeldItem(uint32 i)
5160 // this is only item spell effect applied to main-hand weapon of target player (players in area)
5161 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5162 return;
5164 Player* item_owner = (Player*)unitTarget;
5165 Item* item = item_owner->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
5167 if(!item )
5168 return;
5170 // must be equipped
5171 if(!item ->IsEquipped())
5172 return;
5174 if (m_spellInfo->EffectMiscValue[i])
5176 uint32 enchant_id = m_spellInfo->EffectMiscValue[i];
5177 int32 duration = GetSpellDuration(m_spellInfo); //Try duration index first ..
5178 if(!duration)
5179 duration = m_currentBasePoints[i]+1; //Base points after ..
5180 if(!duration)
5181 duration = 10; //10 seconds for enchants which don't have listed duration
5183 SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
5184 if(!pEnchant)
5185 return;
5187 // Always go to temp enchantment slot
5188 EnchantmentSlot slot = TEMP_ENCHANTMENT_SLOT;
5190 // Enchantment will not be applied if a different one already exists
5191 if(item->GetEnchantmentId(slot) && item->GetEnchantmentId(slot) != enchant_id)
5192 return;
5194 // Apply the temporary enchantment
5195 item->SetEnchantment(slot, enchant_id, duration*1000, 0);
5196 item_owner->ApplyEnchantment(item,slot,true);
5200 void Spell::EffectDisEnchant(uint32 /*i*/)
5202 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5203 return;
5205 Player* p_caster = (Player*)m_caster;
5206 if(!itemTarget || !itemTarget->GetProto()->DisenchantID)
5207 return;
5209 p_caster->UpdateCraftSkill(m_spellInfo->Id);
5211 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(),LOOT_DISENCHANTING);
5213 // item will be removed at disenchanting end
5216 void Spell::EffectInebriate(uint32 /*i*/)
5218 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5219 return;
5221 Player *player = (Player*)unitTarget;
5222 uint16 currentDrunk = player->GetDrunkValue();
5223 uint16 drunkMod = damage * 256;
5224 if (currentDrunk + drunkMod > 0xFFFF)
5225 currentDrunk = 0xFFFF;
5226 else
5227 currentDrunk += drunkMod;
5228 player->SetDrunkValue(currentDrunk, m_CastItem?m_CastItem->GetEntry():0);
5231 void Spell::EffectFeedPet(uint32 i)
5233 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5234 return;
5236 Player *_player = (Player*)m_caster;
5238 if(!itemTarget)
5239 return;
5241 Pet *pet = _player->GetPet();
5242 if(!pet)
5243 return;
5245 if(!pet->isAlive())
5246 return;
5248 int32 benefit = pet->GetCurrentFoodBenefitLevel(itemTarget->GetProto()->ItemLevel);
5249 if(benefit <= 0)
5250 return;
5252 uint32 count = 1;
5253 _player->DestroyItemCount(itemTarget,count,true);
5254 // TODO: fix crash when a spell has two effects, both pointed at the same item target
5256 m_caster->CastCustomSpell(m_caster,m_spellInfo->EffectTriggerSpell[i],&benefit,NULL,NULL,true);
5259 void Spell::EffectDismissPet(uint32 /*i*/)
5261 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5262 return;
5264 Pet* pet = m_caster->GetPet();
5266 // not let dismiss dead pet
5267 if(!pet||!pet->isAlive())
5268 return;
5270 ((Player*)m_caster)->RemovePet(pet,PET_SAVE_NOT_IN_SLOT);
5273 void Spell::EffectSummonObject(uint32 i)
5275 uint32 go_id = m_spellInfo->EffectMiscValue[i];
5277 uint8 slot = 0;
5278 switch(m_spellInfo->Effect[i])
5280 case SPELL_EFFECT_SUMMON_OBJECT_SLOT1: slot = 0; break;
5281 case SPELL_EFFECT_SUMMON_OBJECT_SLOT2: slot = 1; break;
5282 case SPELL_EFFECT_SUMMON_OBJECT_SLOT3: slot = 2; break;
5283 case SPELL_EFFECT_SUMMON_OBJECT_SLOT4: slot = 3; break;
5284 default: return;
5287 uint64 guid = m_caster->m_ObjectSlot[slot];
5288 if(guid != 0)
5290 GameObject* obj = NULL;
5291 if( m_caster )
5292 obj = ObjectAccessor::GetGameObject(*m_caster, guid);
5294 if(obj) obj->Delete();
5295 m_caster->m_ObjectSlot[slot] = 0;
5298 GameObject* pGameObj = new GameObject;
5300 float rot2 = sin(m_caster->GetOrientation()/2);
5301 float rot3 = cos(m_caster->GetOrientation()/2);
5303 float x,y,z;
5304 // If dest location if present
5305 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5307 x = m_targets.m_destX;
5308 y = m_targets.m_destY;
5309 z = m_targets.m_destZ;
5311 // Summon in random point all other units if location present
5312 else
5313 m_caster->GetClosePoint(x,y,z,DEFAULT_WORLD_OBJECT_SIZE);
5315 Map *map = m_caster->GetMap();
5316 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, x, y, z, m_caster->GetOrientation(), 0, 0, rot2, rot3, 0, 1))
5318 delete pGameObj;
5319 return;
5322 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
5323 int32 duration = GetSpellDuration(m_spellInfo);
5324 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5325 pGameObj->SetSpellId(m_spellInfo->Id);
5326 m_caster->AddGameObject(pGameObj);
5328 map->Add(pGameObj);
5329 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5330 data << pGameObj->GetGUID();
5331 m_caster->SendMessageToSet(&data,true);
5333 m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID();
5336 void Spell::EffectResurrect(uint32 i)
5338 if(!unitTarget)
5339 return;
5340 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5341 return;
5343 if(unitTarget->isAlive())
5344 return;
5345 if(!unitTarget->IsInWorld())
5346 return;
5348 switch (m_spellInfo->Id)
5350 // Defibrillate (Goblin Jumper Cables) have 33% chance on success
5351 case 8342:
5352 if (roll_chance_i(67))
5354 m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
5355 return;
5357 break;
5358 // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
5359 case 22999:
5360 if (roll_chance_i(50))
5362 m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
5363 return;
5365 break;
5366 default:
5367 break;
5370 Player* pTarget = ((Player*)unitTarget);
5372 if(pTarget->isRessurectRequested()) // already have one active request
5373 return;
5375 uint32 health = pTarget->GetMaxHealth() * damage / 100;
5376 uint32 mana = pTarget->GetMaxPower(POWER_MANA) * damage / 100;
5378 pTarget->setResurrectRequestData(m_caster->GetGUID(), m_caster->GetMapId(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), health, mana);
5379 SendResurrectRequest(pTarget);
5382 void Spell::EffectAddExtraAttacks(uint32 /*i*/)
5384 if(!unitTarget || !unitTarget->isAlive())
5385 return;
5387 if( unitTarget->m_extraAttacks )
5388 return;
5390 unitTarget->m_extraAttacks = damage;
5393 void Spell::EffectParry(uint32 /*i*/)
5395 if (unitTarget->GetTypeId() == TYPEID_PLAYER)
5397 ((Player*)unitTarget)->SetCanParry(true);
5401 void Spell::EffectBlock(uint32 /*i*/)
5403 if (unitTarget->GetTypeId() != TYPEID_PLAYER)
5404 return;
5406 ((Player*)unitTarget)->SetCanBlock(true);
5409 void Spell::EffectMomentMove(uint32 i)
5411 if(unitTarget->isInFlight())
5412 return;
5414 if( m_spellInfo->rangeIndex== 1) //self range
5416 uint32 mapid = m_caster->GetMapId();
5417 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i]));
5419 // before caster
5420 float fx,fy,fz;
5421 unitTarget->GetClosePoint(fx,fy,fz,unitTarget->GetObjectSize(),dis);
5422 float ox,oy,oz;
5423 unitTarget->GetPosition(ox,oy,oz);
5425 float fx2,fy2,fz2; // getObjectHitPos overwrite last args in any result case
5426 if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(mapid, ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
5428 fx = fx2;
5429 fy = fy2;
5430 fz = fz2;
5431 unitTarget->UpdateGroundPositionZ(fx,fy,fz);
5434 if(unitTarget->GetTypeId() == TYPEID_PLAYER)
5435 ((Player*)unitTarget)->TeleportTo(mapid, fx, fy, fz, unitTarget->GetOrientation(), TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (unitTarget==m_caster ? TELE_TO_SPELL : 0));
5436 else
5437 MapManager::Instance().GetMap(mapid, unitTarget)->CreatureRelocation((Creature*)unitTarget, fx, fy, fz, unitTarget->GetOrientation());
5441 void Spell::EffectReputation(uint32 i)
5443 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5444 return;
5446 Player *_player = (Player*)unitTarget;
5448 int32 rep_change = m_currentBasePoints[i]+1; // field store reputation change -1
5450 uint32 faction_id = m_spellInfo->EffectMiscValue[i];
5452 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
5454 if(!factionEntry)
5455 return;
5457 _player->ModifyFactionReputation(factionEntry,rep_change);
5460 void Spell::EffectQuestComplete(uint32 i)
5462 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5463 return;
5465 Player *_player = (Player*)m_caster;
5467 uint32 quest_id = m_spellInfo->EffectMiscValue[i];
5468 _player->AreaExploredOrEventHappens(quest_id);
5471 void Spell::EffectSelfResurrect(uint32 i)
5473 if(!unitTarget || unitTarget->isAlive())
5474 return;
5475 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5476 return;
5477 if(!unitTarget->IsInWorld())
5478 return;
5480 uint32 health = 0;
5481 uint32 mana = 0;
5483 // flat case
5484 if(damage < 0)
5486 health = uint32(-damage);
5487 mana = m_spellInfo->EffectMiscValue[i];
5489 // percent case
5490 else
5492 health = uint32(damage/100.0f*unitTarget->GetMaxHealth());
5493 if(unitTarget->GetMaxPower(POWER_MANA) > 0)
5494 mana = uint32(damage/100.0f*unitTarget->GetMaxPower(POWER_MANA));
5497 Player *plr = ((Player*)unitTarget);
5498 plr->ResurrectPlayer(0.0f);
5500 plr->SetHealth( health );
5501 plr->SetPower(POWER_MANA, mana );
5502 plr->SetPower(POWER_RAGE, 0 );
5503 plr->SetPower(POWER_ENERGY, plr->GetMaxPower(POWER_ENERGY) );
5505 plr->SpawnCorpseBones();
5507 plr->SaveToDB();
5510 void Spell::EffectSkinning(uint32 /*i*/)
5512 if(unitTarget->GetTypeId() != TYPEID_UNIT )
5513 return;
5514 if(!m_caster || m_caster->GetTypeId() != TYPEID_PLAYER)
5515 return;
5517 Creature* creature = (Creature*) unitTarget;
5518 int32 targetLevel = creature->getLevel();
5520 uint32 skill = creature->GetCreatureInfo()->GetRequiredLootSkill();
5522 ((Player*)m_caster)->SendLoot(creature->GetGUID(),LOOT_SKINNING);
5523 creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5525 int32 reqValue = targetLevel < 10 ? 0 : targetLevel < 20 ? (targetLevel-10)*10 : targetLevel*5;
5527 int32 skillValue = ((Player*)m_caster)->GetPureSkillValue(skill);
5529 // Double chances for elites
5530 ((Player*)m_caster)->UpdateGatherSkill(skill, skillValue, reqValue, creature->isElite() ? 2 : 1 );
5533 void Spell::EffectCharge(uint32 /*i*/)
5535 if(!unitTarget || !m_caster)
5536 return;
5538 float x, y, z;
5539 unitTarget->GetContactPoint(m_caster, x, y, z);
5540 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
5541 ((Creature *)unitTarget)->StopMoving();
5543 // Only send MOVEMENTFLAG_WALK_MODE, client has strange issues with other move flags
5544 m_caster->SendMonsterMove(x, y, z, 0, MOVEMENTFLAG_WALK_MODE, 1);
5546 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5547 MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)->CreatureRelocation((Creature*)m_caster,x,y,z,m_caster->GetOrientation());
5549 // not all charge effects used in negative spells
5550 if ( !IsPositiveSpell(m_spellInfo->Id))
5551 m_caster->Attack(unitTarget,true);
5554 void Spell::EffectSummonCritter(uint32 i)
5556 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5557 return;
5558 Player* player = (Player*)m_caster;
5560 uint32 pet_entry = m_spellInfo->EffectMiscValue[i];
5561 if(!pet_entry)
5562 return;
5564 Pet* old_critter = player->GetMiniPet();
5566 // for same pet just despawn
5567 if(old_critter && old_critter->GetEntry() == pet_entry)
5569 player->RemoveMiniPet();
5570 return;
5573 // despawn old pet before summon new
5574 if(old_critter)
5575 player->RemoveMiniPet();
5577 // summon new pet
5578 Pet* critter = new Pet(MINI_PET);
5580 Map *map = m_caster->GetMap();
5581 uint32 pet_number = objmgr.GeneratePetNumber();
5582 if(!critter->Create(objmgr.GenerateLowGuid(HIGHGUID_PET),
5583 map, pet_entry, pet_number))
5585 sLog.outError("Spell::EffectSummonCritter, spellid %u: no such creature entry %u", m_spellInfo->Id, pet_entry);
5586 delete critter;
5587 return;
5590 float x,y,z;
5591 // If dest location if present
5592 if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5594 x = m_targets.m_destX;
5595 y = m_targets.m_destY;
5596 z = m_targets.m_destZ;
5598 // Summon if dest location not present near caster
5599 else
5600 m_caster->GetClosePoint(x,y,z,critter->GetObjectSize());
5602 critter->Relocate(x,y,z,m_caster->GetOrientation());
5604 if(!critter->IsPositionValid())
5606 sLog.outError("ERROR: Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %d Y: ^%d)", critter->GetGUIDLow(), critter->GetEntry(), critter->GetPositionX(), critter->GetPositionY());
5607 delete critter;
5608 return;
5611 critter->SetUInt64Value(UNIT_FIELD_SUMMONEDBY,m_caster->GetGUID());
5612 critter->SetUInt64Value(UNIT_FIELD_CREATEDBY,m_caster->GetGUID());
5613 critter->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,m_caster->getFaction());
5614 critter->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
5616 critter->AIM_Initialize();
5617 critter->InitPetCreateSpells(); // e.g. disgusting oozeling has a create spell as critter...
5618 critter->SetMaxHealth(1);
5619 critter->SetHealth(1);
5620 critter->SetLevel(1);
5622 // set timer for unsummon
5623 int32 duration = GetSpellDuration(m_spellInfo);
5624 if(duration > 0)
5625 critter->SetDuration(duration);
5627 std::string name = player->GetName();
5628 name.append(petTypeSuffix[critter->getPetType()]);
5629 critter->SetName( name );
5630 player->SetMiniPet(critter);
5632 map->Add((Creature*)critter);
5635 void Spell::EffectKnockBack(uint32 i)
5637 if(!unitTarget || !m_caster)
5638 return;
5640 // Effect only works on players
5641 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5642 return;
5644 float vsin = sin(m_caster->GetAngle(unitTarget));
5645 float vcos = cos(m_caster->GetAngle(unitTarget));
5647 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5648 data.append(unitTarget->GetPackGUID());
5649 data << uint32(0); // Sequence
5650 data << float(vcos); // x direction
5651 data << float(vsin); // y direction
5652 data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
5653 data << float(damage/-10); // Z Movement speed (vertical)
5655 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5658 void Spell::EffectSendTaxi(uint32 i)
5660 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5661 return;
5663 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
5664 if(!entry)
5665 return;
5667 std::vector<uint32> nodes;
5669 nodes.resize(2);
5670 nodes[0] = entry->from;
5671 nodes[1] = entry->to;
5673 uint32 mountid = 0;
5674 switch(m_spellInfo->Id)
5676 case 31606: //Stormcrow Amulet
5677 mountid = 17447;
5678 break;
5679 case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
5680 case 45113: //Quest - Sunwell Daily - Ship Bombing Run
5681 case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
5682 mountid = 22840;
5683 break;
5684 case 34905: //Stealth Flight
5685 mountid = 6851;
5686 break;
5689 ((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
5693 void Spell::EffectPlayerPull(uint32 i)
5695 if(!unitTarget || !m_caster)
5696 return;
5698 // Effect only works on players
5699 if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
5700 return;
5702 float vsin = sin(unitTarget->GetAngle(m_caster));
5703 float vcos = cos(unitTarget->GetAngle(m_caster));
5705 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8+4+4+4+4+4));
5706 data.append(unitTarget->GetPackGUID());
5707 data << uint32(0); // Sequence
5708 data << float(vcos); // x direction
5709 data << float(vsin); // y direction
5710 // Horizontal speed
5711 data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
5712 data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
5714 ((Player*)unitTarget)->GetSession()->SendPacket(&data);
5717 void Spell::EffectDispelMechanic(uint32 i)
5719 if(!unitTarget)
5720 return;
5722 uint32 mechanic = m_spellInfo->EffectMiscValue[i];
5724 Unit::AuraMap& Auras = unitTarget->GetAuras();
5725 for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
5727 next = iter;
5728 ++next;
5729 SpellEntry const *spell = sSpellStore.LookupEntry(iter->second->GetSpellProto()->Id);
5730 if(spell->Mechanic == mechanic || spell->EffectMechanic[iter->second->GetEffIndex()] == mechanic)
5732 unitTarget->RemoveAurasDueToSpell(spell->Id);
5733 if(Auras.empty())
5734 break;
5735 else
5736 next = Auras.begin();
5739 return;
5742 void Spell::EffectSummonDeadPet(uint32 /*i*/)
5744 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5745 return;
5746 Player *_player = (Player*)m_caster;
5747 Pet *pet = _player->GetPet();
5748 if(!pet)
5749 return;
5750 if(pet->isAlive())
5751 return;
5752 if(damage < 0)
5753 return;
5754 pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, 0);
5755 pet->RemoveFlag (UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
5756 pet->setDeathState( ALIVE );
5757 pet->clearUnitState(UNIT_STAT_ALL_STATE);
5758 pet->SetHealth( uint32(pet->GetMaxHealth()*(float(damage)/100)));
5760 pet->AIM_Initialize();
5762 _player->PetSpellInitialize();
5763 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
5766 void Spell::EffectDestroyAllTotems(uint32 /*i*/)
5768 float mana = 0;
5769 for(int slot = 0; slot < MAX_TOTEM; ++slot)
5771 if(!m_caster->m_TotemSlot[slot])
5772 continue;
5774 Creature* totem = ObjectAccessor::GetCreature(*m_caster,m_caster->m_TotemSlot[slot]);
5775 if(totem && totem->isTotem())
5777 uint32 spell_id = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
5778 SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
5779 if(spellInfo)
5780 mana += spellInfo->manaCost * damage / 100;
5781 ((Totem*)totem)->UnSummon();
5785 int32 gain = m_caster->ModifyPower(POWER_MANA,int32(mana));
5786 m_caster->SendEnergizeSpellLog(m_caster, m_spellInfo->Id, gain, POWER_MANA);
5789 void Spell::EffectDurabilityDamage(uint32 i)
5791 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5792 return;
5794 int32 slot = m_spellInfo->EffectMiscValue[i];
5796 // FIXME: some spells effects have value -1/-2
5797 // Possibly its mean -1 all player equipped items and -2 all items
5798 if(slot < 0)
5800 ((Player*)unitTarget)->DurabilityPointsLossAll(damage,(slot < -1));
5801 return;
5804 // invalid slot value
5805 if(slot >= INVENTORY_SLOT_BAG_END)
5806 return;
5808 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5809 ((Player*)unitTarget)->DurabilityPointsLoss(item,damage);
5812 void Spell::EffectDurabilityDamagePCT(uint32 i)
5814 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
5815 return;
5817 int32 slot = m_spellInfo->EffectMiscValue[i];
5819 // FIXME: some spells effects have value -1/-2
5820 // Possibly its mean -1 all player equipped items and -2 all items
5821 if(slot < 0)
5823 ((Player*)unitTarget)->DurabilityLossAll(double(damage)/100.0f,(slot < -1));
5824 return;
5827 // invalid slot value
5828 if(slot >= INVENTORY_SLOT_BAG_END)
5829 return;
5831 if(damage <= 0)
5832 return;
5834 if(Item* item = ((Player*)unitTarget)->GetItemByPos(INVENTORY_SLOT_BAG_0,slot))
5835 ((Player*)unitTarget)->DurabilityLoss(item,double(damage)/100.0f);
5838 void Spell::EffectModifyThreatPercent(uint32 /*effIndex*/)
5840 if(!unitTarget)
5841 return;
5843 unitTarget->getThreatManager().modifyThreatPercent(m_caster, damage);
5846 void Spell::EffectTransmitted(uint32 effIndex)
5848 uint32 name_id = m_spellInfo->EffectMiscValue[effIndex];
5850 GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(name_id);
5852 if (!goinfo)
5854 sLog.outErrorDb("Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast",name_id, m_spellInfo->Id);
5855 return;
5858 float fx,fy,fz;
5860 if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
5862 fx = m_targets.m_destX;
5863 fy = m_targets.m_destY;
5864 fz = m_targets.m_destZ;
5866 //FIXME: this can be better check for most objects but still hack
5867 else if(m_spellInfo->EffectRadiusIndex[effIndex] && m_spellInfo->speed==0)
5869 float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[effIndex]));
5870 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5872 else
5874 float min_dis = GetSpellMinRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5875 float max_dis = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
5876 float dis = rand_norm() * (max_dis - min_dis) + min_dis;
5878 m_caster->GetClosePoint(fx,fy,fz,DEFAULT_WORLD_OBJECT_SIZE, dis);
5881 Map *cMap = m_caster->GetMap();
5883 if(goinfo->type==GAMEOBJECT_TYPE_FISHINGNODE)
5885 if ( !cMap->IsInWater(fx,fy,fz-0.5f)) // Hack to prevent fishing bobber from failing to land on fishing hole
5886 { // but this is not proper, we really need to ignore not materialized objects
5887 SendCastResult(SPELL_FAILED_NOT_HERE);
5888 SendChannelUpdate(0);
5889 return;
5892 // replace by water level in this case
5893 fz = cMap->GetWaterLevel(fx,fy);
5895 // if gameobject is summoning object, it should be spawned right on caster's position
5896 else if(goinfo->type==GAMEOBJECT_TYPE_SUMMONING_RITUAL)
5898 m_caster->GetPosition(fx,fy,fz);
5901 GameObject* pGameObj = new GameObject;
5903 if(!pGameObj->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap,
5904 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5906 delete pGameObj;
5907 return;
5910 int32 duration = GetSpellDuration(m_spellInfo);
5912 switch(goinfo->type)
5914 case GAMEOBJECT_TYPE_FISHINGNODE:
5916 m_caster->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT,pGameObj->GetGUID());
5917 // Orientation3
5918 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 2, 0.88431775569915771 );
5919 // Orientation4
5920 pGameObj->SetFloatValue(GAMEOBJECT_ROTATION + 3, -0.4668855369091033 );
5921 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5923 // end time of range when possible catch fish (FISHING_BOBBER_READY_TIME..GetDuration(m_spellInfo))
5924 // start time == fish-FISHING_BOBBER_READY_TIME (0..GetDuration(m_spellInfo)-FISHING_BOBBER_READY_TIME)
5925 int32 lastSec;
5926 switch(urand(0, 3))
5928 case 0: lastSec = 3; break;
5929 case 1: lastSec = 7; break;
5930 case 2: lastSec = 13; break;
5931 case 3: lastSec = 17; break;
5934 duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
5935 break;
5937 case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
5939 if(m_caster->GetTypeId()==TYPEID_PLAYER)
5941 pGameObj->AddUniqueUse((Player*)m_caster);
5942 m_caster->AddGameObject(pGameObj); // will removed at spell cancel
5944 break;
5946 case GAMEOBJECT_TYPE_FISHINGHOLE:
5947 case GAMEOBJECT_TYPE_CHEST:
5948 default:
5950 break;
5954 pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5956 pGameObj->SetOwnerGUID(m_caster->GetGUID() );
5958 pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
5959 pGameObj->SetSpellId(m_spellInfo->Id);
5961 DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n");
5962 //m_caster->AddGameObject(pGameObj);
5963 //m_ObjToDel.push_back(pGameObj);
5965 cMap->Add(pGameObj);
5967 WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8);
5968 data << uint64(pGameObj->GetGUID());
5969 m_caster->SendMessageToSet(&data,true);
5971 if(uint32 linkedEntry = pGameObj->GetLinkedGameObjectEntry())
5973 GameObject* linkedGO = new GameObject;
5974 if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
5975 fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
5977 linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
5978 linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
5979 linkedGO->SetSpellId(m_spellInfo->Id);
5980 linkedGO->SetOwnerGUID(m_caster->GetGUID() );
5982 MapManager::Instance().GetMap(linkedGO->GetMapId(), linkedGO)->Add(linkedGO);
5984 else
5986 delete linkedGO;
5987 linkedGO = NULL;
5988 return;
5993 void Spell::EffectProspecting(uint32 /*i*/)
5995 if(m_caster->GetTypeId() != TYPEID_PLAYER)
5996 return;
5998 Player* p_caster = (Player*)m_caster;
5999 if(!itemTarget || !(itemTarget->GetProto()->BagFamily & BAG_FAMILY_MASK_MINING_SUPP))
6000 return;
6002 if(itemTarget->GetCount() < 5)
6003 return;
6005 if( sWorld.getConfig(CONFIG_SKILL_PROSPECTING))
6007 uint32 SkillValue = p_caster->GetPureSkillValue(SKILL_JEWELCRAFTING);
6008 uint32 reqSkillValue = itemTarget->GetProto()->RequiredSkillRank;
6009 p_caster->UpdateGatherSkill(SKILL_JEWELCRAFTING, SkillValue, reqSkillValue);
6012 ((Player*)m_caster)->SendLoot(itemTarget->GetGUID(), LOOT_PROSPECTING);
6015 void Spell::EffectSkill(uint32 /*i*/)
6017 sLog.outDebug("WORLD: SkillEFFECT");
6020 void Spell::EffectSummonDemon(uint32 i)
6022 float px = m_targets.m_destX;
6023 float py = m_targets.m_destY;
6024 float pz = m_targets.m_destZ;
6026 Creature* Charmed = m_caster->SummonCreature(m_spellInfo->EffectMiscValue[i], px, py, pz, m_caster->GetOrientation(),TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,3600000);
6027 if (!Charmed)
6028 return;
6030 // might not always work correctly, maybe the creature that dies from CoD casts the effect on itself and is therefore the caster?
6031 Charmed->SetLevel(m_caster->getLevel());
6033 // TODO: Add damage/mana/hp according to level
6035 if (m_spellInfo->EffectMiscValue[i] == 89) // Inferno summon
6037 // Enslave demon effect, without mana cost and cooldown
6038 m_caster->CastSpell(Charmed, 20882, true); // FIXME: enslave does not scale with level, level 62+ minions cannot be enslaved
6040 // Inferno effect
6041 Charmed->CastSpell(Charmed, 22703, true, 0);
6045 /* There is currently no need for this effect. We handle it in BattleGround.cpp
6046 If we would handle the resurrection here, the spiritguide would instantly disappear as the
6047 player revives, and so we wouldn't see the spirit heal visual effect on the npc.
6048 This is why we use a half sec delay between the visual effect and the resurrection itself */
6049 void Spell::EffectSpiritHeal(uint32 /*i*/)
6052 if(!unitTarget || unitTarget->isAlive())
6053 return;
6054 if(unitTarget->GetTypeId() != TYPEID_PLAYER)
6055 return;
6056 if(!unitTarget->IsInWorld())
6057 return;
6059 //m_spellInfo->EffectBasePoints[i]; == 99 (percent?)
6060 //((Player*)unitTarget)->setResurrect(m_caster->GetGUID(), unitTarget->GetPositionX(), unitTarget->GetPositionY(), unitTarget->GetPositionZ(), unitTarget->GetMaxHealth(), unitTarget->GetMaxPower(POWER_MANA));
6061 ((Player*)unitTarget)->ResurrectPlayer(1.0f);
6062 ((Player*)unitTarget)->SpawnCorpseBones();
6066 // remove insignia spell effect
6067 void Spell::EffectSkinPlayerCorpse(uint32 /*i*/)
6069 sLog.outDebug("Effect: SkinPlayerCorpse");
6070 if ( (m_caster->GetTypeId() != TYPEID_PLAYER) || (unitTarget->GetTypeId() != TYPEID_PLAYER) || (unitTarget->isAlive()) )
6071 return;
6073 ((Player*)unitTarget)->RemovedInsignia( (Player*)m_caster );
6076 void Spell::EffectStealBeneficialBuff(uint32 i)
6078 sLog.outDebug("Effect: StealBeneficialBuff");
6080 if(!unitTarget || unitTarget==m_caster) // can't steal from self
6081 return;
6083 std::vector <Aura *> steal_list;
6084 // Create dispel mask by dispel type
6085 uint32 dispelMask = GetDispellMask( DispelType(m_spellInfo->EffectMiscValue[i]) );
6086 Unit::AuraMap const& auras = unitTarget->GetAuras();
6087 for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6089 Aura *aur = (*itr).second;
6090 if (aur && (1<<aur->GetSpellProto()->Dispel) & dispelMask)
6092 // Need check for passive? this
6093 if (aur->IsPositive() && !aur->IsPassive())
6094 steal_list.push_back(aur);
6097 // Ok if exist some buffs for dispel try dispel it
6098 if (!steal_list.empty())
6100 std::list < std::pair<uint32,uint64> > success_list;
6101 int32 list_size = steal_list.size();
6102 // Dispell N = damage buffs (or while exist buffs for dispel)
6103 for (int32 count=0; count < damage && list_size > 0; ++count)
6105 // Random select buff for dispel
6106 Aura *aur = steal_list[urand(0, list_size-1)];
6107 // Not use chance for steal
6108 // TODO possible need do it
6109 success_list.push_back( std::pair<uint32,uint64>(aur->GetId(),aur->GetCasterGUID()));
6111 // Remove buff from list for prevent doubles
6112 for (std::vector<Aura *>::iterator j = steal_list.begin(); j != steal_list.end(); )
6114 Aura *stealed = *j;
6115 if (stealed->GetId() == aur->GetId() && stealed->GetCasterGUID() == aur->GetCasterGUID())
6117 j = steal_list.erase(j);
6118 --list_size;
6120 else
6121 ++j;
6124 // Really try steal and send log
6125 if (!success_list.empty())
6127 int32 count = success_list.size();
6128 WorldPacket data(SMSG_SPELLSTEALLOG, 8+8+4+1+4+count*5);
6129 data.append(unitTarget->GetPackGUID()); // Victim GUID
6130 data.append(m_caster->GetPackGUID()); // Caster GUID
6131 data << uint32(m_spellInfo->Id); // Dispell spell id
6132 data << uint8(0); // not used
6133 data << uint32(count); // count
6134 for (std::list<std::pair<uint32,uint64> >::iterator j = success_list.begin(); j != success_list.end(); ++j)
6136 SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
6137 data << uint32(spellInfo->Id); // Spell Id
6138 data << uint8(0); // 0 - steals !=0 transfers
6139 unitTarget->RemoveAurasDueToSpellBySteal(spellInfo->Id, j->second, m_caster);
6141 m_caster->SendMessageToSet(&data, true);
6146 void Spell::EffectKillCredit(uint32 i)
6148 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6149 return;
6151 ((Player*)unitTarget)->KilledMonster(m_spellInfo->EffectMiscValue[i], 0);
6154 void Spell::EffectQuestFail(uint32 i)
6156 if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
6157 return;
6159 ((Player*)unitTarget)->FailQuest(m_spellInfo->EffectMiscValue[i]);